I'm running the following this code for a codding exercise:
from flask import Flask
from random import randint
rand_n = randint(0, 9)
app = Flask(__name__)
def decorator_header(function):
def wrapper():
return f"<h1>{function()}</h1>"
return wrapper
def check_decorator(function):
def wrapper_function(*args):
result = function(args[0])
if result == "You found me!":
return f"<b style='color:green;'>{result}</b>"
if result == "Too low, try again!":
return f"<b style='color:red;'>{result}</b>"
return f"<b style='color:purple;'>{result}</b>"
return wrapper_function
@app.route('/')
@decorator_header
def guess_number():
return 'Guess a number between 0 and 9'
@app.route('/<number>', endpoint='check_number')
@check_decorator
def check_number(number):
if int(number) < rand_n:
return "Too low, try again!"
if int(number) > rand_n:
return "Too high, try again!"
return "You found me!"
if __name__ == "__main__":
app.run()
If I run the code like this, at first it works: I can load the page that says "Guess a number between 0 and 9" on my browser. Now, when I try to add the number in the url, like URL/1 for example, I get the following error:
[2023-02-19 21:16:23,710] ERROR in app: Exception on /1 [GET]
Traceback (most recent call last):
File "C:\Users\pauLo\venv\lib\site-packages\flask\app.py", line 2528, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\pauLo\venv\lib\site-packages\flask\app.py", line 1825, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\pauLo\venv\lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\pauLo\venv\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
TypeError: wrapper_function() got an unexpected keyword argument 'number'
127.0.0.1 - - [19/Feb/2023 21:16:23] "GET /1 HTTP/1.1" 500 -
If I just change the argument of the wrapper function, like so:
def wrapper_function(number):
result = function(number)
then it works fine. In fact, if I use anything else other than "number", it gives the error above.
Also, if I run the code without using Flask, with the decorator functions like the original and the rest like so:
@decorator_header
def guess_number():
return 'Guess a number between 0 and 9'
@check_decorator
def check_number(number):
if int(number) < rand_n:
return "Too low, try again!"
if int(number) > rand_n:
return "Too high, try again!"
return "You found me!"
guess = input(guess_number())
print(check_number(guess))
It also works just fine. So why do I have to keep the same variable name inside the decoration function? Is Flask.route() returning number=number or something like that? I tried to look into the code for this function, but couldn't figure thigns out.
The problem is that Flask calls your functions with keyword arguments (like check_number(number="1")
), whereas your check_decorator
wrapper expects only positional arguments (def wrapper_function(*args)
).
You could rewrite it like this and it would work:
def check_decorator(function):
def wrapper_function(*args, **kwargs):
result = function(kwargs['number'])
if result == "You found me!":
return f"<b style='color:green;'>{result}</b>"
if result == "Too low, try again!":
return f"<b style='color:red;'>{result}</b>"
return f"<b style='color:purple;'>{result}</b>"
return wrapper_function
But for what you're doing it doesn't make any sense to implement this logic in a decorator -- it should just be part of your check_number
method.