1

I am running check50 on my code and at buy, it cannot validate a purchase because

Log
sending POST request to /login
sending POST request to /buy
exception raised in application: TypeError: 'NoneType' object is not subscriptable

I don't get this error when I'm running the site. I can purchase and display stocks just fine. Check50 won't give me a location in my code and I've read through it to try and find something I call a subscript of that could be a none value but can't find it. All of my code seems like too much do here's my buy and index functions.

  @app.route("/")
@login_required
def index():
    """Show portfolio of stocks"""

    endsum = 0
    companies = {}
    # Declare and define types to start out because dictionaries are confusing
    list_stocks = db.execute("SELECT * FROM portfolio WHERE user=:user_id", user_id = session["user_id"])
    # Returns a list of dictionaries

    for dict_stock in list_stocks:

        # Ensure one entry per company
        if dict_stock['stock'] not in companies:

            # collect the data I'll fill the dictionary with
            #SQL returns a list of dicts but just one here so two steps to get just number
            number_shares = db.execute("SELECT SUM(quantity) FROM portfolio WHERE user = :user_id AND stock = :company",
                user_id = session["user_id"], company = dict_stock['stock'])[0]["SUM(quantity)"]
            # It's very important here that quantity is not wrapped in '', SQL will misinterpret

            if number_shares == 0:
                 break

            # I want to return a dictionary of dictionaries to make it easy to reference
            # Which of course seems complicated now but how else would I keep the data associated
            companies[dict_stock['stock']] = {}

            #lookup returns dict so make our variable the number we want
            cost_stock = lookup(dict_stock['stock'])['price']

            # define the dictionary of dictionaries
            companies[dict_stock['stock']]['shares'] = number_shares
            companies[dict_stock['stock']]['price'] = '%.2f' % cost_stock
            companies[dict_stock['stock']]['total'] = '%.2f' % (number_shares * cost_stock)

            endsum += number_shares * cost_stock
        else:
            pass

    return render_template("index.html", stocks = companies, endsum = '%.2f' % endsum)


@app.route("/buy", methods=["GET", "POST"])
@login_required
def buy():
    """Buy shares of stock"""

    # User submitted the form

    if request.method == "POST":

        # Get these from the form to make it a one-time deal
        symbol = request.form.get("symbol")
        shares = request.form.get("shares")

        # Ensure that user input a symbol
        if not symbol:
            return apology("must provide symbol", 400)

        # Ensure that user input is of length 5 or less to be valid
        elif len(str(symbol)) > magic:
            return apology("must provide valid symbol", 400)

        # Lookup returns None when not found
        if lookup(symbol) == None:
            return apology("invalid symbol / lookup error", 400)

        # Check for int
        if not shares:
            return apology("1Invalid number of stocks", 400)
        if not shares.isdigit():
            return apology("2iNvalid number of stocks", 400)
        shares = int(shares)
        if shares < 1:
            return apology("3inValid number of stocks", 400)

        # If it all clears now's a good time to reach for information
        symboldict = lookup(symbol)

        # Check for if there's enough cash
        if db.execute("SELECT cash FROM users WHERE id = :user_id",
            user_id = session["user_id"])[0]["cash"] < symboldict['price'] * shares:
            return apology("not enough cash", 420)

        # at this point everything is checked for and we can buy the stock
        # insert transaction
        db.execute("INSERT INTO portfolio (user, stock, cost, quantity) VALUES (:user_id, :stock, :price, :number)",
            user_id = session["user_id"], stock = symboldict['name'], price = symboldict['price'], number = shares)

        # subtract cash
        db.execute("UPDATE users SET cash = cash - :total WHERE id = :user",
            total = symboldict['price'] * shares, user = session["user_id"])

        return redirect("/")

    # Reached via GET
    else:
        return render_template("buy.html")
  • My code is returning the same error. When running the site it runs ok and returns index.html in exactly the same format as the staff solution, but it still fails the same check. Did you manage to figure out what to do? – AvocadoFire Mar 30 '18 at 9:56
  • @AvocadoFire I went and looked through what I changed and the key thing I changed was the SQL query at the beginning of index(). I selected stock which still returns a list of dictionaries, instead of a list of lists of dictionaries. My thought is that when selecting all, there were empty entries, creating NoneType errors. – Zachary Ellison Mar 31 '18 at 19:32
1

Either: Is lookup always returning something? You could check this before applying a subscript.

Reasoning is that Yahoo shut down its API a few weeks ago. Have you updated your helpers.py file? The one on the CS50 repo has a fallback for another service (sadly does not provide company names, will return the symbol instead).

Or: Is your database query always returning something? You could check this before applying a subscript.

| improve this answer | |
  • Are there any other reasons for this issue? I implemented "try" for every item that I subscript in my code and even checked every item in every dict for isinstance(var, type(none)). It works perfectly on my own web server but check50 has a problem with it and I cannot figure out why. – Nils Kummert Jan 20 '18 at 13:36

You must log in to answer this question.

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