TypeError: argument of type 'NoneType' is not iterable after an if statement

10,790

Solution 1

I can only guess but looks like it's because of this particular code block -

try: js = json.loads(str(data))
except: js = None
if 'status' not in js or js['status'] != 'OK':
    print ('==== Failure To Retrieve ====')
    print (data)
    continue

Your json.loads(str(data)) raises an Exception due to some error, since it is being caught by except, you assign

js = None

And in the next line you do an in comparison on js but js is None or NoneType, you can not iterate over NoneType, therefore -

TypeError: argument of type 'NoneType' is not iterable

And here's more about the in operator of Python

Solution 2

In the code:

try: js = json.loads(str(data))
except: js = None

You're telling Python that if an exception is thrown in json.loads you want to set js to None. Then in the following if-statement, you reference js directly. The problem here is that an exception was indeed thrown but your code following this check does not take that into account. To fix your problem, you should change your if-statement to be:

if (not js or 'status' not in js or js['status'] != 'OK'):

assuming you want the statements inside the if-statement to execute on error.

As an aside, please don't inline try or except or if statements. It makes your code very difficult to follow.

Solution 3

It's pretty obvious: if there's any exception with loading the JSON information, you set js to None, but immediately try to use it as a sequence. Adding the print statement makes this clear:

try: js = json.loads(str(data))
except: js = None

print("TRACE: js=", js)
if 'status' not in js or js['status'] != 'OK':

Output:

Enter location: Hillsborough
Retrieving http://maps.googleapis.com/maps/api/geocode/json?address=Hillsborough&sensor=false
Retrieved 279 characters
TRACE: js= None
Traceback (most recent call last):
  File "so.py", line 21, in <module>
    if 'status' not in js or js['status'] != 'OK':
TypeError: argument of type 'NoneType' is not iterable

Instead, issue and error message and loop back for another try:

try:
    js = json.loads(str(data))
except: 
    print("Map fetch failed; try again\n")
    continue

Output:

Enter location: Hillsborough
Retrieving http://maps.googleapis.com/maps/api/geocode/json?address=Hillsborough&sensor=false
Retrieved 279 characters
Map fetch failed; try again

Enter location: Chicago
Retrieving http://maps.googleapis.com/maps/api/geocode/json?address=Chicago&sensor=false
Retrieved 279 characters
Map fetch failed; try again
Share:
10,790

Related videos on Youtube

Heena
Author by

Heena

Updated on June 04, 2022

Comments

  • Heena
    Heena almost 2 years

    I am trying to get the 2-letter state code for a city from user input, but getting the TypeError: argument of type 'NoneType' is not iterable error message. Not sure how to fix it to get the right results? This is the line that's giving the error message:

    if 'status' not in js or js['status'] != 'OK':
    

    Below is the full code:

    import urllib
    import urllib.request as ur
    import json
    
    serviceurl = 'http://maps.googleapis.com/maps/api/geocode/json?'
    
    while True:
        address = input('Enter location: ')
        if len(address) < 1 : break
    
        url = serviceurl + urllib.parse.urlencode({'sensor':'false', 'address': address})
        print ('Retrieving', url)
        uh = ur.urlopen(url)
        data = uh.read()
        print ('Retrieved',len(data),'characters')
    
        try: js = json.loads(str(data))
        except: js = None
        if 'status' not in js or js['status'] != 'OK':
            print ('==== Failure To Retrieve ====')
            print (data)
            continue
    
        print (json.dumps(js, indent=4))
        '''
        lat = js["results"][0]["geometry"]["location"]["lat"]
        lng = js["results"][0]["geometry"]["location"]["lng"]
        print ('lat',lat,'lng',lng)
        ''' #not necessary for this assignment
        location = js['results'][0]['formatted_address']
        print (location)
    
        results = js['results'][0]
        address_components = results["address_components"]
        country = 0;
        for each_dict in address_components:
            types = each_dict["types"]
            if types == ["country", "political"]:
                country = 1;
                print ("The two character country  code is:", each_dict["short_name"])
    
        if country == 0:
            print ("Location isn't in any country")
    

    How do I fix it?

    • Jordan
      Jordan over 5 years
      Would you mind fixing the indentation? It also looks like some of your code at the top isn't formatted as code.
    • tgikal
      tgikal over 5 years
      It's failing at js = json.loads(str(data)) and you're setting js = None, then trying to iterate over it.
    • tgikal
      tgikal over 5 years
      If you check data it says " '{\n "error_message" : "Keyless access to Google Maps Platform is deprecated. Please use an API key with all your API calls to avoid service interruption. For further details please refer to g.co/dev/maps-no-account",\n "results" : [],\n "status" : "OVER_QUERY_LIMIT"\n}\n' "
    • Heena
      Heena over 5 years
      @tgikal Ahh, I thought it was the exception if clause. What can I do to fix it?
    • tgikal
      tgikal over 5 years
      It's an answer for an android question, but I think the accepted answer is still valid in this situation. stackoverflow.com/questions/52352941/… Basically you need to get a API key and include it in the URL.
    • tgikal
      tgikal over 5 years
      Or just use googlemap's module... github.com/googlemaps/google-maps-services-python
    • tgikal
      tgikal over 5 years
      Looks like google requires you to set up billing to get a API key, but they give you $200 a month, which equates to millions of this style of query per month. cloud.google.com/maps-platform