Shandrill
Shandrill

Reputation: 13

What is causing an IndexError when accessing the first element in a non-empty list?

Bear with me if this is too simple, I'm just starting to learn to code.

Task:

Create a weather report from an API call. Ask for city, look up the city from web page and return the weather forecast for the next five days. Then ask for a city again, continue until CTRL-C is hit.

Build on, if asked for a city name that doesn't exit, ask for a city again.

City?
> fhusi
City not found
City?
> London
Here is the weather in London
2021-01-22: Heavy Cloud 6.2°C
2021-01-23: Heavy Cloud 3.8°C
2021-01-24: Heavy Rain 3.5°C
2021-01-25: Light Rain 3.8°C
2021-01-26: Showers 4.5°C
Traceback (most recent call last):
  File "weather.py", line 45, in <module>
    main()
  File "weather.py", line 32, in main
    city = search_city(query)
  File "weather.py", line 19, in search_city
    return seach_response[0]
IndexError: list index out of range

Here is my code: And yes, there is a lot of comments in it, that's how I remember my errors

# pylint: disable=missing-docstring

import sys
import urllib.parse
import requests

BASE_URI = "https://www.metaweather.com"


def search_city(query):
    # : Look for a given city and disambiguate between several candidates. Return one city (or None)
    seach_response = requests.get("https://www.metaweather.com/api/location/search/?query="+query).json() # [0] return results as dict format
    # print(requests.get("https://www.metaweather.com/api/location/search/?query="+query).json)
    # print(seach_response.status_code) --> remember to remove .json() from seach to see status code
    # if seach_response.status_code != 200: --> didn't work, as a empty list is returned if city doesn't exit and not an error code
    if seach_response == []:
        print("City not found")
        main()
    return seach_response[0]


def weather_forecast(woeid):
    # : Return a 5-element list of weather forecast for a given woeid
    weather_response = requests.get(f'https://www.metaweather.com/api/location/{woeid}/').json()
    #print(weather_response) --use https://jsonformatter.curiousconcept.com/# to see the data nicely and pick relevant data
    weather = weather_response['consolidated_weather'][:5]
    return weather


def main():
    query = input("City?\n> ")
    city = search_city(query)
    #print(city) --control of code
    woeid = city['woeid']
    forecast = weather_forecast(woeid)
    # : Display weather forecast for a given city
    print(f"Here is the weather in {city['title']}")
    for predition in forecast:
        print(f"{predition['applicable_date']}: {predition['weather_state_name']} {round(predition['the_temp'],1)}\N{DEGREE SIGN}C")


if __name__ == '__main__':
    try:
        while True:
            main()
    except KeyboardInterrupt:
        print('\nGoodbye!')
        sys.exit(0)

Upvotes: 1

Views: 166

Answers (1)

Countour-Integral
Countour-Integral

Reputation: 1154

The problem is at your search_city(query) function. Take a look at the following lines.

if seach_response == []: # empty list
    print("City not found")
    main() # Execute main again
# Opps, main has executed and the function is still going
# but searc_response is an empty list so search_response[0] is going to be out of bounds
return seach_response[0]

To fix the above you need to return main() instead of main(). After this in main you should check if search_city(query) returned None.

So your code should look like this

def search_city(query):
    seach_response = requests.get("https://www.metaweather.com/api/location/search/?query="+query).json() # [0] return results as dict format
    if seach_response == []:
        print("City not found")
        return main() # return
    return seach_response[0]

and also

def main():
    query = input("City?\n> ")
    city = search_city(query)
    if city is None: 
        return
    woeid = city['woeid'] # here if city is None it will throw an exception
    forecast = weather_forecast(woeid)
    print(f"Here is the weather in {city['title']}")
    for predition in forecast:
        print(f"{predition['applicable_date']}: {predition['weather_state_name']} {round(predition['the_temp'],1)}\N{DEGREE SIGN}C")

Upvotes: 1

Related Questions