When I test my code myself, it seems to work, but check50
is showing otherwise. Quote has a single problem, and buy has two problems, but I am not able to figure out where in the code is the error and what is the error. Please may somebody help?
Application.py:
import os
from cs50 import SQL
from flask import Flask, flash, jsonify, redirect, render_template, request, session
from flask_session import Session
from tempfile import mkdtemp
from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
from werkzeug.security import check_password_hash, generate_password_hash
from helpers import apology, login_required, lookup, usd
# Configure application
app = Flask(__name__)
# Ensure templates are auto-reloaded
app.config["TEMPLATES_AUTO_RELOAD"] = True
# Ensure responses aren't cached
@app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
# Custom filter
app.jinja_env.filters["usd"] = usd
# Configure session to use filesystem (instead of signed cookies)
app.config["SESSION_FILE_DIR"] = mkdtemp()
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Configure CS50 Library to use SQLite database
db = SQL("sqlite:///finance.db")
# Make sure API key is set
if not os.environ.get("API_KEY"):
raise RuntimeError("API_KEY not set")
@app.route("/")
@login_required
def index():
"""Show portfolio of stocks"""
id = session['user_id']
username = db.execute("SELECT username FROM users WHERE id = :id;", id=id)[0]['username']
cashed = db.execute("SELECT cash FROM users WHERE id = :id;", id=id)[0]['cash']
owned = db.execute("SELECT symbol, shares FROM shares WHERE username = :username;", username=username)
stocks = []
totaled = cashed
cash = usd(cashed)
for owns in owned:
dict = {}
symbol = owns['symbol']
shares = owns['shares']
dict.update( {'symbol': symbol.upper()} )
dict.update( {'shares': shares} )
lookedup = lookup(symbol)
totaled += lookedup['price']
dict.update( {'name': lookedup['name']} )
dict.update( {'total': int(lookedup['price']) * shares} )
dict.update( {'price': usd(lookedup['price'])} )
stocks.append(dict)
dict = {}
dict.update( {'symbol': 'CASH'} )
dict.update( {'shares': ''} )
dict.update( {'name': ''} )
dict.update( {'total': cash} )
stocks.append(dict)
total = usd(totaled)
return render_template("index.html", total=total, cash=cash, stocks=stocks)
@app.route("/buy", methods=["GET", "POST"])
@login_required
def buy():
"""Buy shares of stock"""
if request.method == "GET":
return render_template("buy.html")
elif request.method =="POST":
id = session['user_id']
username = str(db.execute("SELECT username FROM users WHERE id=:id;", id=id)[0]['username'])
cash = int(db.execute("SELECT cash FROM users WHERE id=:id;", id=id)[0]['cash'])
symbol = request.form.get("symbol")
shares = int(request.form.get("shares"))
lookedup = lookup(symbol)
if not lookedup:
return apology("Invalid Symbol")
price = int(lookedup['price']) * shares
if cash < price:
return apology("Unaffordable")
result = db.execute("SELECT shares FROM shares WHERE username = :username AND symbol = :symbol;", username=username, symbol=symbol)
if not result:
db.execute("INSERT INTO shares (username, symbol, shares) VALUES(:username, :symbol, :shares);", username=username, symbol=symbol, shares=shares)
else:
resultant = int(result[0]['shares']) + shares
db.execute("UPDATE shares SET shares = :shares WHERE symbol = :symbol AND username = :username;", shares=resultant, symbol=symbol, username=username)
db.execute("UPDATE users SET cash = :cash WHERE id = :id;", cash=(cash-price), id=id)
return redirect("/")
@app.route("/check", methods=["GET"])
def check():
"""Return true if username available, else false, in JSON format"""
name = {"username": request.args.get('username')}
names = db.execute("SELECT username FROM 'users' WHERE username=:username;", username=name)
if len(name) < 1 or name in names:
return jsonify(False)
return jsonify(True)
@app.route("/history")
@login_required
def history():
"""Show history of transactions"""
return redirect("/")
@app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in"""
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# Ensure username was submitted
if not request.form.get("username"):
return apology("Missing username", 403)
# Ensure password was submitted
elif not request.form.get("password"):
return apology("Missing Password", 403)
# Query database for username
rows = db.execute("SELECT * FROM users WHERE username = :username",
username=request.form.get("username"))
# Ensure username exists and password is correct
if len(rows) != 1 or not check_password_hash(rows[0]["password"], request.form.get("password")):
return apology("Invalid Username and/or Password", 403)
# Remember which user has logged in
session["user_id"] = rows[0]['id']
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("login.html")
@app.route("/logout")
def logout():
"""Log user out"""
# Forget any user_id
session.clear()
# Redirect user to login form
return redirect("/")
@app.route("/quote", methods=["GET", "POST"])
@login_required
def quote():
"""Get stock quote."""
if request.method == "GET":
return render_template("quote.html")
elif request.method == "POST":
quote = lookup(request.form.get('symbol'))
if not quote:
return apology("Invalid symbol")
return render_template("quoted.html", name=quote['name'], symbol=quote['symbol'], price=quote['price'])
@app.route("/register", methods=["GET", "POST"])
def register():
"""Register user"""
if request.method == "GET":
return render_template("register.html")
elif request.method == "POST":
name = request.form.get("username")
password = request.form.get("password")
confirmation = request.form.get("confirmation")
if not name:
return apology("Missing username")
if not password:
return apology("Missing password")
if not confirmation:
return apology("Missing confirmation")
if password != confirmation:
return apology("Passwords did not match")
password = generate_password_hash(password)
result = db.execute("INSERT INTO users (username, password, cash) VALUES(:username, :password, 10000);", username=name, password=password)
if not result:
return apology("Username already exists")
username = str(db.execute("SELECT username FROM users WHERE id=:id;", id=result)[0]['username'])
session["user_id"] = result
return redirect("/")
@app.route("/sell", methods=["GET", "POST"])
@login_required
def sell():
"""Sell shares of stock"""
id = session['user_id']
username = str(db.execute("SELECT * FROM users WHERE id = :id;", id=id)[0]['username'])
if request.method == "GET":
shares = db.execute("SELECT symbol FROM shares WHERE username = :username", username=username)
symbols = []
for share in shares:
symbols.append(share['symbol'].upper())
return render_template("sell.html", symbols=symbols)
elif request.method =="POST":
symbol = request.form.get("symbol").lower()
shared = request.form.get("shares")
if shared % 1 != 0:
return apology("Fractional shares")
else:
shares = int(shared)
owned = int(db.execute("SELECT shares FROM shares WHERE username = :username AND symbol = :symbol;", username=username, symbol=symbol)[0]['shares'])
lookedup = lookup(symbol)
if not lookedup:
return apology("Invalid Symbol")
price = int(lookedup['price']) * shares
if shares > owned:
return apology("Too Many Shares")
if shares == owned:
db.execute("DELETE FROM shares WHERE username = :username AND symbol = :symbol;", username=username, symbol=symbol)
else:
cash = int(db.execute("SELECT cash FROM users WHERE id = :id;", id=id)[0]['cash'])
result = cash - price
newshares = owned - shares
db.execute("UPDATE shares SET shares = :shares WHERE symbol = :symbol AND username = :username;", shares=newshares, symbol=symbol, username=username)
db.execute("UPDATE users SET cash = :cash WHERE id = :id;", cash=result, id=id)
return redirect("/")
def errorhandler(e):
"""Handle error"""
if not isinstance(e, HTTPException):
e = InternalServerError()
return apology(e.name, e.code)
# Listen for errors
for code in default_exceptions:
app.errorhandler(code)(errorhandler)
Buy.html:
{% extends "layout.html" %}
{% block title %}
Buy
{% endblock %}
{% block main %}
<form action="/buy" method="post">
<div class="form-group">
<input autocomplete="off" class="form-control" autofocus name="symbol" placeholder="Ticker Symbol" type="text">
</div>
<div class="form-group">
<input autocomplete="off" class="form-control" min="1" name="shares" placeholder="Shares" type="number">
</div>
<button class="btn btn-primary" type="submit">Buy</button>
</form>
{% endblock %}
Quote.html:
{% extends "layout.html" %}
{% block title %}
Quote
{% endblock %}
{% block main %}
<form action="/quote" method="post" id="registration">
<div class="form-group">
<input autocomplete="off" autofocus class="form-control" name="symbol" placeholder="Ticker Symbol" type="text">
</div>
<button class="btn btn-primary" type="submit">Quote</button>
</form>
{% endblock %}
Quoted.html:
{% extends "layout.html" %}
{% block title %} Quoted {% endblock %}
{% block main %} A share of {{ name }} ({{ symbol }}) costs {{ price | usd }}. {% endblock %}
Index.html:
{% extends "layout.html" %}
{% block title %} Portfolio {% endblock %}
{% block main %} Symbol Name Shares Price TOTAL {{ total }} {% for stock in stocks %} {{ stock['symbol'] }} {{ stock['name'] }} {{ stock['shares'] }} {{ stock['price'] | usd }} {{ stock['total'] | usd }} {% endfor %} {% endblock %}
Error:
ERROR:application:Exception on / [GET]
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/ubuntu/pset8/finance/helpers.py", line 34, in decorated_function
return f(*args, **kwargs)
File "/home/ubuntu/pset8/finance/application.py", line 72, in index
return render_template("index.html", total=total, cash=cash, stocks=stocks)
File "/usr/local/lib/python3.7/site-packages/flask/templating.py", line 140, in render_template
ctx.app,
File "/usr/local/lib/python3.7/site-packages/flask/templating.py", line 120, in _render
rv = template.render(context)
File "/usr/local/lib/python3.7/site-packages/jinja2/asyncsupport.py", line 76, in render
return original_render(self, *args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 1008, in render
return self.environment.handle_exception(exc_info, True)
File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/jinja2/_compat.py", line 37, in reraise
raise value.with_traceback(tb)
File "/home/ubuntu/pset8/finance/templates/index.html", line 1, in top-level template code
{% extends "layout.html" %}
File "/home/ubuntu/pset8/finance/templates/layout.html", line 66, in top-level template code
{% block main %}{% endblock %}
File "/home/ubuntu/pset8/finance/templates/index.html", line 30, in block "main"
<td>{{ stock['price'] | usd }}</td>
File "/home/ubuntu/pset8/finance/helpers.py", line 63, in usd
return f"${value:,.2f}"
TypeError: unsupported format string passed to Undefined.__format__
Thank you in advance.