I'm having trouble with the quote method. When I go to the quote tab of my CS50 Finance site, it says:

AttributeError: 'NoneType' object has no attribute 'startswith'

Seems as if lookup is returning None automatically - although I'm not sure if I'm correct on this. Could someone help me figure out what I'm doing wrong?

Here is my code in application.py:

@app.route("/quote", methods=["GET", "POST"])
def quote():
    """Get stock quote."""

    quote = lookup(request.form.get("search"))
    return render_template("quoted.html", name=quote)

This is my code for quote.html:

{% extends "layout.html" %}

{% block title %}
    Search Stock
{% endblock %}

{% block main %}
    <form action="{{ url_for('quote') }}" method="post">
            <div class="form-group">
                <input class="form-control" name="search" placeholder="Search" type="text"/>
            <div class="form-group">
                <button class="btn btn-default" type="submit">Search</button>
{% endblock %}

And this is my code in quoted.html:

{% block title %}
{% endblock %}

{% block main %}
        {{ name }}
{% endblock %}

Lastly, here is the lookup method in helpers.py, which I don't think I need to alter:

def lookup(symbol):
    """Look up quote for symbol."""

    # reject symbol if it starts with caret
    if symbol.startswith("^"):
        return None

    # reject symbol if it contains comma
    if "," in symbol:
        return None

    # query Yahoo for quote
    # http://stackoverflow.com/a/21351911
        url = "http://download.finance.yahoo.com/d/quotes.csv?f=snl1&s={}".format(symbol)
        webpage = urllib.request.urlopen(url)
        datareader = csv.reader(webpage.read().decode("utf-8").splitlines())
        row = next(datareader)
        return None

    # ensure stock exists
        price = float(row[2])
        return None

    # return stock's name (as a str), price (as a float), and (uppercased) symbol (as a str)
    return {
        "name": row[1],
        "price": price,
        "symbol": row[0].upper()

Thank you for helping!


The error is telling you that the argument sent to lookup is None type. It expects a string type. Instead of looking "forward" to lookup, you need to look "backwards" to discover why request.form.get("search") is returning a None type.

Won't request.form.get("search") return None if you have visted quote with a GET method (as from a link)?

Review this from the spec:

Odds are you’ll want to create two new templates (e.g., quote.html and quoted.html). When a user visits /quote via GET, render one of those templates, inside of which should be an HTML form that submits to /quote via POST. In response to a POST, quote can render that second template, embedding within it one or more values from lookup.

Routine needs to do different things depending on whether it's been called with a GET or a POST.

  • Thank you. I haven't solved it yet, but I've updated my post to include quote.html, which is where request.form.get("search") is coming from. Do you by any chance know what is causing this malfunction now? – Ethan Teo Jan 25 '17 at 18:02
  • More explanation added to answer. – DinoCoderSaurus Jan 25 '17 at 20:09

You must log in to answer this question.

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