0

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.

1

Your issue is that you aren't formatted your numbers such that you are probably displaying 28 instead of 28.00

You are given a this:

# Custom filter
app.jinja_env.filters["usd"] = usd

that can be used as a format in jinja.

{{ price | usd }}

for example will format the price variable as $28.00 for you.

Your fractional problem is because you are not making sure that the shares you get from the form are actually an integer. You need to check that from the server side as well, not just rely on your html form for that.

| improve this answer | |
  • Thank you, curiouswiki. I added the price | usd to my index and quoted page, but it raised an exception (shown above). I also added checking for the fractional part, but I could not check it (because of the exception). – AK2150 Aug 7 '19 at 6:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .