Click here to Skip to main content
15,887,596 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm sorry if I missed anything. Let me know and I'll try to get you the information. I'm using Python 3.12.0 and am trying to code a relatively simple weather program that pulls information using json. When I run the program, I get the following errors:

For gust:
Traceback (most recent call last):
  File "C:\Users\Jdzenorb\Desktop\weather.py", line 72, in <module>      
    my_city = City("Indianapolis",39.777778,-86.177222,units="imperial",)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Jdzenorb\Desktop\weather.py", line 22, in __init__      
    self.get_data()
  File "C:\Users\Jdzenorb\Desktop\weather.py", line 39, in get_data      
    self.gust = self.response_json["wind"]["gust"]
                ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
KeyError: 'gust'


For description:
Traceback (most recent call last):
  File "C:\Users\Jdzenorb\Desktop\weather.py", line 72, in <module>
    my_city = City("Indianapolis",39.777778,-86.177222,units="imperial",)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Jdzenorb\Desktop\weather.py", line 22, in __init__
    self.get_data()
  File "C:\Users\Jdzenorb\Desktop\weather.py", line 44, in get_data
    self.description = self.response_json["weather"]["description"]
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
TypeError: list indices must be integers or slices, not str


Here is the code that I have written. I'm having issues with pulling the "gust" and "description" and with converting the time from the json string to a readable time.

import requests

class City:
    def __init__(self,name,lat,lon,units="metric",pressure="standard",humidity="standard",
                 distance="metric",speed="metric",deg="standard",gust="metric",all="standard",sunrise="standard",
                 sunset="standard",timezone="standard",description="standard"):
        self.name = name
        self.lat = lat
        self.lon = lon
        self.units = units
        self.pressure = pressure
        self.humidity = humidity
        self.distance = distance
        self.speed = speed
        self.deg = deg
        self.gust = gust
        self.all = all
        self.sunrise = sunrise
        self.sunset = sunset
        self.timezone = timezone
        self.description = description
        self.get_data()
    def get_data(self):
        try:
            response = requests.get(f"https://api.openweathermap.org/data/2.5/weather?units={self.units}&lat={self.lat}&lon={self.lon}&appid=634b43c85eda738d2acfabac85f322d4")
        except ConnectionError:
            print("No internet connection. Please connect to internet.")

        self.response_json = response.json()
        self.temp = self.response_json["main"]["temp"]
        self.feels_like = self.response_json["main"]["feels_like"]
        self.temp_min = self.response_json["main"]["temp_min"]
        self.temp_max = self.response_json["main"]["temp_max"]
        self.pressure = self.response_json["main"]["pressure"]
        self.humidity = self.response_json["main"]["humidity"]
        self.distance = self.response_json["visibility"]
        self.speed = self.response_json["wind"]["speed"]
        self.deg = self.response_json["wind"]["deg"]
        self.gust = self.response_json["wind"]["gust"]
        self.all = self.response_json["clouds"]["all"]
        self.sunrise = self.response_json["sys"]["sunrise"]
        self.sunset = self.response_json["sys"]["sunset"]
        self.timezone = self.response_json["timezone"]
        self.description = self.response_json["weather"]["description"]
    def weather(self):
        pass
    def main(self):
        units_symbol = "C"
        if self.units == "imperial":
            units_symbol = "F"
        print(f"In {self.name} it is currently {self.temp}°{units_symbol}")
        print(f"It feels like: {self.feels_like}°{units_symbol}")
        print(f"Today's High: {self.temp_max}°{units_symbol}")
        print(f"Today's Low: {self.temp_min}°{units_symbol}")
        print(f"The Pressure is: {self.pressure}hPa")
        print(f"The Humidity is: {self.humidity}%")
    def visibility(self):
        print(f"The visibility is: {self.distance}m")
    def wind(self):
        units_symbol = "m/s"
        if self.units == "imperial":
            units_symbol = "mph"
        print(f"The wind speed is: {self.speed}{units_symbol} from {self.deg}°")
        print(f"Wind Gusts up to: {self.gust}{units_symbol}")
    def clouds(self):
        print(f"Cloud cover: {self.all}%")
    def sys(self):
        print(f"Sunrise will occur at {self.sunrise} {self.timezone}")
        print(f"Sunset will occur at {self.sunset} {self.timezone}")
    

my_city = City("Indianapolis",39.777778,-86.177222,units="imperial",)
my_city.weather()
my_city.main()
my_city.visibility()
my_city.wind()
my_city.clouds()
my_city.sys()


Here is the json data:

{
    "coord": {
        "lon": -86.1772,
        "lat": 39.7778
    },
    "weather": [
        {
            "id": 800,
            "main": "Clear",
            "description": "clear sky",
            "icon": "01d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 285.33,
        "feels_like": 283.73,
        "temp_min": 282.36,
        "temp_max": 286.85,
        "pressure": 1027,
        "humidity": 43
    },
    "visibility": 10000,
    "wind": {
        "speed": 2.57,
        "deg": 240
    },
    "clouds": {
        "all": 0
    },
    "dt": 1700063188,
    "sys": {
        "type": 2,
        "id": 2089097,
        "country": "US",
        "sunrise": 1700051352,
        "sunset": 1700087374
    },
    "timezone": -18000,
    "id": 4259418,
    "name": "Indianapolis",
    "cod": 200
}


What I have tried:

For the gust, when I comment it out line 39 (and subsequently everything else to prevent errors, the code will run.
self.gust = self.response_json["wind"]["gust"]


For the description error, I can do the same thing as I do for gust (line 44) and get the same results.
self.description = self.response_json["weather"]["description"]


For the time, I've tried importing and using datetime and trying to format it as "%Y-%m-%dT%H:%M:%S.%f%z", but nothing will change it.
Posted
Comments
[no name] 15-Nov-23 11:32am    
I see no "gust" in your data; which implies it is optional; which means you can't blindly attempt to access it. You have to make allowances for "optional fields" (whatever that may be); particularly when dealing with numerics versus strings in "text data".
DarthGaba 15-Nov-23 11:47am    
I went back in and noticed that. When I was first writing the script yesterday there was a gust, but the data updates (thus no gust now). Can I use try/except to make gust "0" when no data is available?

So how do I make the allowance for the description?
[no name] 15-Nov-23 12:18pm    
The "simplest" solution is to supply defaults for the missing fields in the data. The other is to understand the "deserialization" process and how missing fields are handled; i.e. what is there in memory after you "load".

1 solution

Take a look at the content of response_json variable:
{'coord': {'lon': -86.1772, 'lat': 39.7778}, 'weather': [{'id': 800, 'main': 'Clear', 'description': 'clear sky', 'icon': '01d'}], 'base': 'stations', 'main': {'temp': 63.86, 'feels_like': 61.36, 'temp_min': 61.18, 'temp_max': 66.63, 'pressure': 1025, 'humidity': 30}, 'visibility': 10000, 'wind': {'speed': 10.36, 'deg': 210}, 'clouds': {'all': 0}, 'dt': 1700073771, 'sys': {'type': 2, 'id': 2089097, 'country': 'US', 'sunrise': 1700051352, 'sunset': 1700087374}, 'timezone': -18000, 'id': 4259418, 'name': 'Indianapolis', 'cod': 200}


A ["weather"] is a list! So, when you're trying to access it as a dictionary, you'll receive the following error message:
Quote:
TypeError: list indices must be integers or slices, not str

Tip: loop through the elements on the list or use index:
Python
print(self.response_json["weather"][0]["description"])


BTW: there's no ["gust"] entry under ["weather"]!

As to the sunrise and sunset time...
I think json returns time in seconds. So, you can convert it by using similar method:
Python
import datatime

dtformat = '%d/%m/%Y %H:%M'
tzinfo = datetime.timezone(datetime.timedelta(seconds=18000))
dt_Indianapolis = datetime.datetime.fromtimestamp(1700078972, tzinfo)
print(f"Indianapolis standard time: {dt_Indianapolis.strftime(dtformat)}")
sunr = datetime.datetime.fromtimestamp(1700051352, tzinfo)
print(f"Indianapolis sunrise at: {sunr.strftime(dtformat)}")
suns = datetime.datetime.fromtimestamp(1700087374, tzinfo)
print(f"Indianapolis sunset at: {suns.strftime(dtformat)}")
 
Share this answer
 
v3
Comments
DarthGaba 15-Nov-23 15:26pm    
@Maciej Los thank you for the fix with description. The json updates and we don't have any gusts today.

Do you have any advice regarding the time? The json spits out seconds (1700051352) and the time zone (-18000). I've tried using datetime.time() and defining "sunrise" and "sunset" in the __init__ as "%Y-%m-%dT%H:%M:%S.%f%z", but it didn't work.
Maciej Los 15-Nov-23 15:52pm    
Yes, see updated answer.
[EDIT]
Have you tried my code to convert seconds into time?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900