:( buy handles valid purchase application raised an exception (see log for details) Log sending POST request to /login sending POST request to /buy exception raised in application: TypeError: 'NoneType' object is not subscriptable

Above is the output from check50 I've been scratching my head about for a few days now.

1) I've checked that lookup() is returning values. It's always defaulting to the backup as Yahoo seems to be down, so I'm never geting a 'name' of a stock, always the symbol for both the symbol part and the name part.

2) The code runs fine when I try it myself as a website. It returns a newly populated portfolio of stocks with the current price of the shares showing and the total value of each share showing on the right, plus the user's current balance and grand total, just like the staff solution.

3) I don't fully understand what check50 is looking for. It's finding a 'NoneType' so it's presumably parsing something that hasn't populated correctly. Any ideas?

@app.route("/buy", methods=["GET", "POST"])
def buy():
"""Buy shares of stock"""
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":

    # Get symbol, check validity
    symbol = lookup(request.form.get("symbol"))
    if lookup(request.form.get("symbol")) == None:
        return apology("invalid symbol", 400)

        shares = float(request.form.get("shares"))
    except ValueError:
        return apology("Not a number", 400)

    # Ensure a number is entered and it is positve
    if request.form.get("shares") == None or float(request.form.get("shares")) < 0:
        return apology("invalid number", 400)

    # Check that the number entered is whole
    if is_whole(request.form.get("shares")) == False:
        return apology("must be a whole number", 400)

    # Check user can afford it.
    shares = float(request.form.get("shares"))
    acc_balance = db.execute("SELECT cash FROM users WHERE id = :user_id", user_id=session["user_id"])
    if acc_balance[0]["cash"] - (symbol["price"] * shares) < 0:
        return apology("cannot afford", 400)

    # Insert who bought, which symbol, how many shares, time, at what price into table
        db.execute("INSERT INTO transactions (symbol, user_id, at_price, time_date,shares) \
        VALUES (:symbol, :user_id, :at_price, :time_date,:shares)", \
        symbol=symbol["symbol"], user_id=session["user_id"], at_price=float(symbol["price"]), time_date=datetime.datetime.now().strftime("%d-%m-%y %H:%M"),shares=request.form.get("shares"))
        # Update user's cash
        db.execute("UPDATE users SET cash = cash - :price WHERE id = :user_id", \
        price=float(symbol["price"]) * float(request.form.get("shares")), user_id=session["user_id"])

        return redirect("/")

# User reached route via GET (as by clicking a link or via redirect)
    return render_template("buy.html")


This is index.html
def index():
    """Show portfolio of stocks"""
    # Think dicts in a list...
    txns = db.execute("SELECT symbol, shares FROM transactions WHERE user_id = :id", id=session["user_id"])
    # Add the symbols of the stocks on hand to a list
    basket = get_basket(txns)
    portfolio = get_portfolio(basket)
    gtotal = 0.0
    for i in range(len(portfolio)):
        for j in range(len(portfolio[i])):
            # Insert the current share price into the portfolio
            symbol = lookup(portfolio[i][j]["symbol"])
            portfolio[i][j].update({"price" : symbol["price"]})
            portfolio[i][j].update({"total" : symbol["price"] * portfolio[i][j]["shares"]})
            gtotal = gtotal + portfolio[i][j]["total"]
    # Get users balance
    cash = db.execute("SELECT cash FROM users WHERE id = :id", id=session["user_id"])
    cash = cash[0]["cash"]
    # Get total balance
    total = cash + gtotal
    # Pass: stocks, # shares, price per stock, total value of each holding, cash bal, g-total
    return render_template("index.html", portfolio=portfolio, cash=cash, total=gtotal + cash)


  • Do the details in the log file give more info that may help in finding the problem? Mar 31, 2018 at 13:38
  • @DinoCoderSaurus Hi, thanks for the reply. Please see the section in italics at the top of my question. That's what the log file is listing for /buy. Mar 31, 2018 at 14:16
  • Oh, I was hoping there was more to it than that :( If I was a betting man (which I'm not!) I would concentrate on index. You could try short circuiting index, call render_template("index.html") first thing. check50 will still fail, but if it does NOT give the Nonetype error, the problem is likely index. If it does give the error, the problem is likely buy. Mar 31, 2018 at 17:59
  • @DinoCoderSaurus You were right :) return redirect("/") to redirect("index.html") which has given me different log output. I'm now on :( buy handles valid purchase expected to find "112.00" in page, but it wasn't found Log sending POST request to /login sending POST request to /buy checking that "112.00" is in page Thanks for the tip :) Will post an answer when I crack it. Mar 31, 2018 at 18:29

1 Answer 1


To pass the "buy handles valid purhase" stage, Check50 needs something along the lines of the following to appear following buying stock:

You bought FB at $159.79 per stock which is worth $159.79

You now have $5,865.72 left to spend

I've chosen to display a bought.html page with the above information on following a purchase. So rather than re-direct to ("/") I'm rendering bought like this:

return render_template("bought.html",symbol=symbol["name"], price=float(symbol["price"]), value_of_holding=shares * float(symbol["price"]), cash=float(remaining_cash[0]["cash"]))

So, it's fixed. Another way to do this may be to display the last most recent purchase above the table on index.html, or as an alert, but this works and it will do for now :)

  • do you have your bought.html somewhere so I can see it? This error is taking me ages now and I'm desperate to fix it Dec 15, 2018 at 14:37
  • this helped me! mine finally worked once I added the cash balance left to spend. thank you! this drove me crazy especially when everything technically works as spec. Jul 30, 2021 at 8:38

You must log in to answer this question.

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