Abhay Salvi
Abhay Salvi

Reputation: 1119

Flask Celery TypeError: send_() got multiple values for argument 'time_'

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

Answers (1)

Tom&#225;š Linhart
Tom&#225;š Linhart

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

Related Questions