Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialBrendan Whiting
Front End Web Development Techdegree Graduate 84,738 PointsAttributeError: 'tuple' object has no attribute '__call__'
I'm going to avoid posting all my tacocat challenge code if I can, it's a mess, just trying to understand this one error message for now.
Here is macros.html from s5v1
{% macro render_field(field) %}
{% if field.errors %}
<div class="u-full-width field-errors">
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{{ field.label }}
{{ field(class="u-full-width") }}
{% endmacro %}
I get this Jinja2 error:
File "/home/treehouse/workspace/templates/macros.html", line 12, in <module> {{ field(class="u-full-width") }} AttributeError: 'tuple' object has no attribute 'call'
So what I don't understand is that in the previous app we made, there was a similar line of code where it would appear we are "calling" this tuple like a function.
Here is macros.html from s4v5
{% macro render_field(field) %}
<div class="field">
{% if field.errors %}
{% for error in field.errors %}
<div class="notification error">{{ error }}</div>
{% endfor %}
{% endif %}
{{ field(placeholder="hey there") }}
</div>
{% endmacro %}
How is it that {{ field(placeholder="hey there") }}
isn't causing the same problem?
3 Answers
Chris Freeman
Treehouse Moderator 68,441 PointsI created a mash-up of your code and my tacocat solution and could not reproduce your error. I did find two other errors in your tacocat.py
file. Without the rest of your files, I don't think I can reproduce your error,
-
redirect
not defined -
login_manager.user_loader
not defined
# add missing redirect
from flask import redirect
# Hack add missing user_loader -cf
@login_manager.user_loader
def load_user(userid):
try:
return models.User.get(models.User.id == userid)
except DoesNotExist:
return None
# Hack route -cf
@app.route('/register', methods=('Get', 'Post'))
def register():
return render_template('index.html', tacos=models.Taco.select())
# Hack route -cf
@app.route('/taco', methods=('Get', 'Post'))
def taco():
return render_template('index.html', tacos=models.Taco.select())
# Hack route -cf
@app.route('/logout', methods=('Get', 'Post'))
def logout():
return render_template('index.html', tacos=models.Taco.select())
with this additional code, the mash-up produced:
$ python app_tests.py
.FF......FF
======================================================================
FAIL: test_empty_db (__main__.TacoViewsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "app_tests.py", line 129, in test_empty_db
self.assertIn("no tacos yet", rv.get_data(as_text=True).lower())
AssertionError: 'no tacos yet' not found in '<!doctype html>\n<html>\n <head>\n <title>tacocat</title>\n <link rel="stylesheet" href="/static/css/normalize.css">\n <link rel="stylesheet" href="/static/css/skeleton.css">\n <link rel="stylesheet" href="/static/css/tacocat.css">\n </head>\n <body>\n \n \n \n\n <div class="container">\n <div class="row">\n <div class="u-full-width">\n <nav class="menu">\n <!-- menu goes here -->\n \n <p>welcome!!</p>\n <a href="/login">log in</a>\n <a href="/register">sign up</a>\n \n </nav>\n \n\n<form method=\'post\' action=\'\'>\n <div style="display:none;"><input id="csrf_token" name="csrf_token" type="hidden" value="none"></div>\n <div class="row">\n <div class="six columns">\n \n \n\n<label for="protein">protein</label>\n <input class="u-full-width" id="protein" name="protein" type="text" value="">\n\n </div>\n <div class="six columns">\n \n \n\n<label for="shell">shell</label>\n <input class="u-full-width" id="shell" name="shell" type="text" value="">\n\n </div>\n </div>\n <div class="row">\n <div class="six columns">\n \n\n<label for="cheese">cheese?</label>\n <input class="u-full-width" id="cheese" name="cheese" type="checkbox" value="y">\n\n </div>\n <div class="six columns">\n \n\n<label for="extras">extras?</label>\n <input class="u-full-width" id="extras" name="extras" type="text" value="">\n\n </div>\n </div>\n <div class="u-full-width">\n <input type="submit" class="button-primary" value="create">\n </div>\n</form>\n\n\n </div>\n </div>\n <footer>\n <p>an mvp web app made with flask on <a href="http://teamtreehouse.com">treehouse</a>.</p>\n </footer>\n </div>\n </body>\n</html>'
======================================================================
FAIL: test_taco_create (__main__.TacoViewsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "app_tests.py", line 144, in test_taco_create
self.assertEqual(rv.status_code, 302)
AssertionError: 200 != 302
======================================================================
FAIL: test_logout (__main__.UserViewsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "app_tests.py", line 108, in test_logout
self.assertEqual(rv.status_code, 302)
AssertionError: 200 != 302
======================================================================
FAIL: test_registration (__main__.UserViewsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "app_tests.py", line 86, in test_registration
self.assertEqual(rv.status_code, 302)
AssertionError: 200 != 302
----------------------------------------------------------------------
Ran 11 tests in 22.317s
FAILED (failures=4)
Chris Freeman
Treehouse Moderator 68,441 PointsYour code from macro.html
is exactly the code I used to passed the challenge. Many times an error is cause by some upstream activity meaning that macro.html
is at the end of the process tacocat.login()
→ login.html
→ macros.html
. So it could be an error with a field that is passed down the chain.
What does your tacocat.py
and login.html
look like?
Brendan Whiting
Front End Web Development Techdegree Graduate 84,738 PointsMy code right now is kind of a disaster. I had this strategy of trying to write code to pass each test, rather than trying to make a fully formed app and then try and pass the tests. But anyways:
tacocat.py
from flask import Flask, render_template, flash, url_for
from flask.ext.bcrypt import check_password_hash
from flask.ext.login import (LoginManager, login_user, logout_user,
login_required, current_user)
import forms
import models
DEBUG = True
PORT = 8000
HOST = '0.0.0.0'
app = Flask(__name__)
app.secret_key = 'lalal!'
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
@app.route('/')
def index():
form = forms.TacoForm()
return render_template('taco.html', form=form)
@app.route('/login', methods=('GET', 'POST'))
def login():
form = forms.LoginForm()
if form.validate_on_submit():
try:
user = models.User.get(models.User.email == form.email.data)
except models.DoesNotExist:
flash("Your email or password doesn't match!", "error")
else:
if check_password_hash(user.password, form.password.data):
login_user(user)
flash("You've been logged in!", "success")
return redirect(url_for('index'))
else:
flash("Your email or password doesn't match!", "error")
return render_template('login.html', form=form)
if __name__ == '__main__':
models.initialize()
try:
models.User.create_user(
email='kenneth@teamtreehouse.com',
password='password',
)
except ValueError:
pass
app.run(debug=DEBUG, host=HOST, port=PORT)
login.html
{% extends 'layout.html' %}
{% from 'macros.html' import render_field %}
{% block content %}
<form method='POST' action=''>
{{ form.hidden_tag() }}
<div class="row">
<div class="six columns">
{{ render_field(form.email) }}
</div>
<div class="six columns">
{{ render_field(form.password) }}
</div>
</div>
<div class="u-full-width">
<input type="submit" class="button-primary" value="Login">
</div>
</form>
{% endblock %}
Chris Grazioli
31,225 Pointsdo you need to import redirect?