I'm trying to implement a task in a loop for one discord bot using the discord.py library.
In synthesis, this is what my code looks like:
class RoblinBot(commands.Bot):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.path = ".roblin"
self.fsettings = f"{self.path}/settings.json"
self.listen_urls = False
self.links = []
self.high_activity = False
self.setup()
def setup(self):
if not os.path.exists(self.path):
os.makedirs(self.path)
self.settings = Settings(self.fsettings)
def reset(self):
for f in os.listdir(self.path):
os.remove(os.path.join(self.path, f))
self.setup()
async def on_ready(self):
print("BOT READY")
try:
sync = await bot.tree.sync()
print(f"SYNCHED {len(sync)} COMMAND(S)")
await self.add_cog(ListenWebsite(self))
except Exception as e:
logger.exception(e)
and the cog (containing the task), is defined on the same file as:
class ListenWebsite(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.check_for_articles.start()
@tasks.loop(seconds=CHECK_EVERY)
async def check_for_articles(self):
print("this is a looped message")
if not self.listen_urls:
return
for url in self.settings.urls:
source = requests.get(url)
soup = BeautifulSoup(source.content, 'lxml')
raw = []
links = []
for link in soup.find_all('a', href=True):
raw.append(str(link.get('href')))
for item in raw:
match = re.search("(?P<url>https?://[^\s]+)", item)
if match is not None:
links.append((match.group("url")))
links = list(set(links)) # remove duplicates
for link in links:
if link.count("-")<=1: # should not be an article
links.remove(link)
print(url)
print(links)
# compare self.links and links to see if new articles are found
if not self.links:
new_links = list(set(links)-set(self.links))
for link in new_links:
await self.settings.channel.send(
f"Baby wake up! New article just dropped: {link}"
)
self.links.append(link)
else:
self.links = links
@check_for_articles.before_loop
async def before_check_for_articles(self):
print('waiting for bot to be ready...')
await self.wait_until_ready()
@check_for_articles.error
async def check_for_articles(self, error: Exception):
logger.exception(error)
however I cannot seem to make it work, I keep getting 'function' object has no attribute 'start'
when the cog's init is called.
One thing to be noted is that before this I tried putting the task also inside the bot's class and outside, however I also got the same error. It's as if the tasks.loop
decorator isn't there, and I'm baffled since according to every example I can find, my code should just work.
Maybe there's something I'm missing, but I don't know what it could be.
What I tried:
What I expected to happened: In all listed cases, I would've expected the check_for_articles
function to inherit all the methods bestowed by the tasks.loop
decorator.
What actually resulted: None of the methods of tasks.loop
are given to the function.
You're overwriting your check_for_articles
task in the error handler:
class ListenWebsite(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.check_for_articles.start()
@tasks.loop(seconds=CHECK_EVERY)
async def check_for_articles(self):
...
@check_for_articles.before_loop
async def before_check_for_articles(self):
...
@check_for_articles.error
async def check_for_articles_error(self, error: Exception): # error was here
...