Reputation: 1119
I'm using Celery
for running my function in the background. All the code was working fine but when I actually used celery
then it keeps telling me the same error:
File "C:\Users\intel\AppData\Local\Programs\Python\Python38\Lib\site-packages\celery\app\task.py", line 526, in apply_async
check_arguments(*(args or ()), **(kwargs or {}))
TypeError: send_() got multiple values for argument 'time_'
What I'm doing is actually scraping a webpage and sending an email through scheduling by taking the time argument from the URL. Like: http://127.0.0.1:5000/10
takes 10 seconds.
I'm doing so, so that it doesn't need to wait for 10 seconds to send an email first and then display the webpage.
Here's my code:
import time
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import ssl
import smtplib
from jinja2 import Template
from flask import Flask, render_template
from test import *
from celery import Celery
# Broker URL for RabbitMQ task queue
broker_url = 'amqp://guest@localhost'
app = Flask(__name__)
celery = Celery(app.name, broker=broker_url)
# Your celery configurations in a celeryconfig.py
# celery.config_from_object('celeryconfig')
celery.conf.update(
CELERY_DEFAULT_QUEUE="main",
CELERY_DEFAULT_EXCHANGE="main",
CELERY_DEFAULT_EXCHANGE_TYPE="direct",
CELERY_DEFAULT_ROUTING_KEY="main",
)
sender_email = "[email protected]"
receiver_email = "[email protected]"
password = "pass"
message = MIMEMultipart("alternative")
message["Subject"] = "multipart test"
message["From"] = sender_email
message["To"] = receiver_email
# Create the plain-text and HTML version of your message
t = Template("""\
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:v="urn:schemas-microsoft-com:vml">
<body>
<h1>Hello!</h1>
{% for i in result %}
<li>{{i}}</li>
{% endfor %}
</body>
</html>
""")
@celery.task(bind=True)
def send_(time_, result):
time.sleep(time_)
html = t.render(result=result)
part2 = MIMEText(html, "HTML")
message.attach(part2)
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(sender_email, password)
server.sendmail(
sender_email, receiver_email, message.as_string()
)
@app.route('/<time>')
def hello_world(time):
from bs4 import BeautifulSoup
import requests as req
resp = req.get('https://zulie.medium.com/')
soup = BeautifulSoup(resp.text, "lxml")
lst = []
for div in soup.find_all("div"):
soup = BeautifulSoup(str(div), 'html5lib')
div_tag = soup.find()
try:
title = div_tag.section.div.h1.a.text
if title not in lst:
lst.append(title)
except:
pass
send_.delay(time_=int(time), result=lst)
return render_template('hello.html', result=lst)
if __name__ == '__main__':
app.run(debug=True)
Remember: You need to type your own password to send the mail
Upvotes: 1
Views: 1733
Reputation: 10210
You define your task as a bound task (using bind=True
) so the first argument to the task will always be the task instance. You are missing self
in your function definition as a first parameter so Celery will supply the task instance to the time_
parameter (as a positional argument). When you call the task using
send_.delay(time_=int(time), result=lst)
you are supplying time_
again, this time as a keyword argument. Thus, you receive the error about multiple values for time_
parameter.
Either change the task function definition to
@celery.task(bind=True)
def send_(self, time_, result):
...
or remove the bind=True
in the task decorator
@celery.task
def send_(time_, result):
...
as you don't seem to be needing it anyway (see this for what the use cases are).
Upvotes: 3