csparpa / pyowm

A Python wrapper around the OpenWeatherMap web API
https://pyowm.readthedocs.io
MIT License
791 stars 175 forks source link

Error not properly handled when api call goes wrong #186

Closed DB-CL closed 7 years ago

DB-CL commented 7 years ago

Hi there !

I'm using home assistant, a project using pyowm and I was reporting a bug in this project but they told me I should report here (https://github.com/home-assistant/home-assistant/issues/7512).

Something goes wrong when the API call fail for some reason.

Here is the traceback I got from home assistant. The error comes from pyowm files :

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/entity.py", line 225, in async_update_ha_state
    None, self.update)
  File "/usr/lib/python3.4/asyncio/futures.py", line 388, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup
    value = future.result()
  File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result
    raise self._exception
  File "/usr/lib/python3.4/concurrent/futures/thread.py", line 54, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.4/dist-packages/homeassistant/components/sensor/openweathermap.py", line 124, in update
    self.owa_client.update()
  File "/usr/local/lib/python3.4/dist-packages/homeassistant/util/__init__.py", line 303, in wrapper
    result = method(*args, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/homeassistant/components/sensor/openweathermap.py", line 181, in update
    obs = self.owm.weather_at_coords(self.latitude, self.longitude)
  File "/root/.homeassistant/deps/pyowm/webapi25/owm25.py", line 248, in weather_at_coords
    return self._parsers['observation'].parse_JSON(json_data)
  File "/root/.homeassistant/deps/pyowm/webapi25/observationparser.py", line 39, in parse_JSON
    d = loads(JSON_string)
  File "/usr/lib/python3.4/json/__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'NoneType'

I looked a little bit into it and this is effectively wrong : a call to JSON.load() is done on a NoneType object, which leads to a crash : https://github.com/csparpa/pyowm/blob/master/pyowm/webapi25/observationparser.py#L39

The call comes from this line : https://github.com/csparpa/pyowm/blob/master/pyowm/webapi25/owm25.py#L248 and the method producing the None object is there https://github.com/csparpa/pyowm/blob/master/pyowm/commons/weather_client.py#L71

According to the documentation this method should return a string, and it's returning None in some cases.

I think a check is missing in _lookup_cache_or_invoke_API of the same file.

csparpa commented 7 years ago

Thanks for notifying this! I think the issue is on the IF series starting here: https://github.com/csparpa/pyowm/blob/master/pyowm/commons/weather_client.py#L58 because it's missing an ELSE statement

I will anyway add extra checks on the entity parser classes before they get to load the dict from the input JSON string, so to raise an exception whenever that input string is None

csparpa commented 7 years ago

Fixed with https://github.com/csparpa/pyowm/commit/93e2b8b77f96abc0428c8817ac411dc77169c6fc