Skip to content

Commit

Permalink
Refactored to new global json saving and loading (home-assistant#10677)
Browse files Browse the repository at this point in the history
* Refactored to new global json saving and loading

* Fixed emulated_hue tests

* Removed unnecassary error handling

* Added missing newline

* Remove unused imports

* Fixed linting error

* Moved _load_json wrapper out of the config class
  • Loading branch information
mnigbur authored and balloob committed Nov 20, 2017
1 parent 7695ca2 commit a83e741
Show file tree
Hide file tree
Showing 15 changed files with 74 additions and 349 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@ docs/build
desktop.ini
/home-assistant.pyproj
/home-assistant.sln
/.vs/home-assistant/v14
/.vs/*
27 changes: 4 additions & 23 deletions homeassistant/components/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
https://home-assistant.io/components/axis/
"""

import json
import logging
import os

Expand All @@ -22,6 +21,7 @@
from homeassistant.helpers import discovery
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.entity import Entity
from homeassistant.util.json import load_json, save_json


REQUIREMENTS = ['axis==14']
Expand Down Expand Up @@ -103,9 +103,9 @@ def configuration_callback(callback_data):
return False

if setup_device(hass, config, device_config):
config_file = _read_config(hass)
config_file = load_json(hass.config.path(CONFIG_FILE))
config_file[serialnumber] = dict(device_config)
_write_config(hass, config_file)
save_json(hass.config.path(CONFIG_FILE), config_file)
configurator.request_done(request_id)
else:
configurator.notify_errors(request_id,
Expand Down Expand Up @@ -163,7 +163,7 @@ def axis_device_discovered(service, discovery_info):
serialnumber = discovery_info['properties']['macaddress']

if serialnumber not in AXIS_DEVICES:
config_file = _read_config(hass)
config_file = load_json(hass.config.path(CONFIG_FILE))
if serialnumber in config_file:
# Device config previously saved to file
try:
Expand Down Expand Up @@ -274,25 +274,6 @@ def signal_callback(action, event):
return True


def _read_config(hass):
"""Read Axis config."""
path = hass.config.path(CONFIG_FILE)

if not os.path.isfile(path):
return {}

with open(path) as f_handle:
# Guard against empty file
return json.loads(f_handle.read() or '{}')


def _write_config(hass, config):
"""Write Axis config."""
data = json.dumps(config)
with open(hass.config.path(CONFIG_FILE), 'w', encoding='utf-8') as outfile:
outfile.write(data)


class AxisDeviceEvent(Entity):
"""Representation of a Axis device event."""

Expand Down
5 changes: 2 additions & 3 deletions homeassistant/components/ecobee.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from homeassistant.helpers import discovery
from homeassistant.const import CONF_API_KEY
from homeassistant.util import Throttle
from homeassistant.util.json import save_json

REQUIREMENTS = ['python-ecobee-api==0.0.10']

Expand Down Expand Up @@ -110,12 +111,10 @@ def setup(hass, config):
if 'ecobee' in _CONFIGURING:
return

from pyecobee import config_from_file

# Create ecobee.conf if it doesn't exist
if not os.path.isfile(hass.config.path(ECOBEE_CONFIG_FILE)):
jsonconfig = {"API_KEY": config[DOMAIN].get(CONF_API_KEY)}
config_from_file(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig)
save_json(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig)

NETWORK = EcobeeData(hass.config.path(ECOBEE_CONFIG_FILE))

Expand Down
39 changes: 13 additions & 26 deletions homeassistant/components/emulated_hue/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
https://home-assistant.io/components/emulated_hue/
"""
import asyncio
import json
import logging

import voluptuous as vol
Expand All @@ -16,8 +15,10 @@
)
from homeassistant.components.http import REQUIREMENTS # NOQA
from homeassistant.components.http import HomeAssistantWSGI
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.deprecation import get_deprecated
import homeassistant.helpers.config_validation as cv
from homeassistant.util.json import load_json, save_json
from .hue_api import (
HueUsernameView, HueAllLightsStateView, HueOneLightStateView,
HueOneLightChangeView)
Expand Down Expand Up @@ -187,7 +188,7 @@ def entity_id_to_number(self, entity_id):
return entity_id

if self.numbers is None:
self.numbers = self._load_numbers_json()
self.numbers = _load_json(self.hass.config.path(NUMBERS_FILE))

# Google Home
for number, ent_id in self.numbers.items():
Expand All @@ -198,7 +199,7 @@ def entity_id_to_number(self, entity_id):
if self.numbers:
number = str(max(int(k) for k in self.numbers) + 1)
self.numbers[number] = entity_id
self._save_numbers_json()
save_json(self.hass.config.path(NUMBERS_FILE), self.numbers)
return number

def number_to_entity_id(self, number):
Expand All @@ -207,7 +208,7 @@ def number_to_entity_id(self, number):
return number

if self.numbers is None:
self.numbers = self._load_numbers_json()
self.numbers = _load_json(self.hass.config.path(NUMBERS_FILE))

# Google Home
assert isinstance(number, str)
Expand Down Expand Up @@ -244,25 +245,11 @@ def is_entity_exposed(self, entity):

return is_default_exposed or expose

def _load_numbers_json(self):
"""Set up helper method to load numbers json."""
try:
with open(self.hass.config.path(NUMBERS_FILE),
encoding='utf-8') as fil:
return json.loads(fil.read())
except (OSError, ValueError) as err:
# OSError if file not found or unaccessible/no permissions
# ValueError if could not parse JSON
if not isinstance(err, FileNotFoundError):
_LOGGER.warning("Failed to open %s: %s", NUMBERS_FILE, err)
return {}

def _save_numbers_json(self):
"""Set up helper method to save numbers json."""
try:
with open(self.hass.config.path(NUMBERS_FILE), 'w',
encoding='utf-8') as fil:
fil.write(json.dumps(self.numbers))
except OSError as err:
# OSError if file write permissions
_LOGGER.warning("Failed to write %s: %s", NUMBERS_FILE, err)

def _load_json(filename):
"""Wrapper, because we actually want to handle invalid json."""
try:
return load_json(filename)
except HomeAssistantError:
pass
return {}
37 changes: 4 additions & 33 deletions homeassistant/components/fan/insteon_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/fan.insteon_local/
"""
import json
import logging
import os
from datetime import timedelta

from homeassistant.components.fan import (
ATTR_SPEED, SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH,
SUPPORT_SET_SPEED, FanEntity)
from homeassistant.helpers.entity import ToggleEntity
import homeassistant.util as util
from homeassistant.util.json import load_json, save_json

_CONFIGURING = {}
_LOGGER = logging.getLogger(__name__)
Expand All @@ -33,7 +32,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Insteon local fan platform."""
insteonhub = hass.data['insteon_local']

conf_fans = config_from_file(hass.config.path(INSTEON_LOCAL_FANS_CONF))
conf_fans = load_json(hass.config.path(INSTEON_LOCAL_FANS_CONF))
if conf_fans:
for device_id in conf_fans:
setup_fan(device_id, conf_fans[device_id], insteonhub, hass,
Expand Down Expand Up @@ -88,44 +87,16 @@ def setup_fan(device_id, name, insteonhub, hass, add_devices_callback):
configurator.request_done(request_id)
_LOGGER.info("Device configuration done!")

conf_fans = config_from_file(hass.config.path(INSTEON_LOCAL_FANS_CONF))
conf_fans = load_json(hass.config.path(INSTEON_LOCAL_FANS_CONF))
if device_id not in conf_fans:
conf_fans[device_id] = name

if not config_from_file(
hass.config.path(INSTEON_LOCAL_FANS_CONF),
conf_fans):
_LOGGER.error("Failed to save configuration file")
save_json(hass.config.path(INSTEON_LOCAL_FANS_CONF), conf_fans)

device = insteonhub.fan(device_id)
add_devices_callback([InsteonLocalFanDevice(device, name)])


def config_from_file(filename, config=None):
"""Small configuration file management function."""
if config:
# We're writing configuration
try:
with open(filename, 'w') as fdesc:
fdesc.write(json.dumps(config))
except IOError as error:
_LOGGER.error('Saving config file failed: %s', error)
return False
return True
else:
# We're reading config
if os.path.isfile(filename):
try:
with open(filename, 'r') as fdesc:
return json.loads(fdesc.read())
except IOError as error:
_LOGGER.error("Reading configuration file failed: %s", error)
# This won't work yet
return False
else:
return {}


class InsteonLocalFanDevice(FanEntity):
"""An abstract Class for an Insteon node."""

Expand Down
53 changes: 10 additions & 43 deletions homeassistant/components/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,21 @@
https://home-assistant.io/ecosystem/ios/
"""
import asyncio
import os
import json
import logging
import datetime

import voluptuous as vol
# from voluptuous.humanize import humanize_error

from homeassistant.helpers import config_validation as cv

from homeassistant.helpers import discovery

from homeassistant.core import callback

from homeassistant.components.http import HomeAssistantView

from homeassistant.remote import JSONEncoder

from homeassistant.const import (HTTP_INTERNAL_SERVER_ERROR,
HTTP_BAD_REQUEST)
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import discovery
from homeassistant.util.json import load_json, save_json


_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -174,36 +169,6 @@
CONFIG_FILE_PATH = ""


def _load_config(filename):
"""Load configuration."""
if not os.path.isfile(filename):
return {}

try:
with open(filename, "r") as fdesc:
inp = fdesc.read()

# In case empty file
if not inp:
return {}

return json.loads(inp)
except (IOError, ValueError) as error:
_LOGGER.error("Reading config file %s failed: %s", filename, error)
return None


def _save_config(filename, config):
"""Save configuration."""
try:
with open(filename, 'w') as fdesc:
fdesc.write(json.dumps(config, cls=JSONEncoder))
except (IOError, TypeError) as error:
_LOGGER.error("Saving config file failed: %s", error)
return False
return True


def devices_with_push():
"""Return a dictionary of push enabled targets."""
targets = {}
Expand Down Expand Up @@ -244,7 +209,7 @@ def setup(hass, config):

CONFIG_FILE_PATH = hass.config.path(CONFIGURATION_FILE)

CONFIG_FILE = _load_config(CONFIG_FILE_PATH)
CONFIG_FILE = load_json(CONFIG_FILE_PATH)

if CONFIG_FILE == {}:
CONFIG_FILE[ATTR_DEVICES] = {}
Expand Down Expand Up @@ -305,7 +270,9 @@ def post(self, request):

CONFIG_FILE[ATTR_DEVICES][name] = data

if not _save_config(CONFIG_FILE_PATH, CONFIG_FILE):
try:
save_json(CONFIG_FILE_PATH, CONFIG_FILE)
except HomeAssistantError:
return self.json_message("Error saving device.",
HTTP_INTERNAL_SERVER_ERROR)

Expand Down
Loading

0 comments on commit a83e741

Please sign in to comment.