Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored to new global json saving and loading #10677

Merged
merged 7 commits into from
Nov 20, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No newline at end of file.

27 changes: 4 additions & 23 deletions homeassistant/components/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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 +104,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 +164,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 @@ -273,26 +274,6 @@ def signal_callback(action, event):
hass.add_job(device.start)
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
35 changes: 11 additions & 24 deletions homeassistant/components/emulated_hue/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,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 +189,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 = self._load_json(self.hass.config.path(NUMBERS_FILE))

# Google Home
for number, ent_id in self.numbers.items():
Expand All @@ -198,7 +200,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 +209,7 @@ def number_to_entity_id(self, number):
return number

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

# Google Home
assert isinstance(number, str)
Expand Down Expand Up @@ -244,25 +246,10 @@ 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."""
def _load_json(self, filename):
"""Wrapper, because we actually want to handle invalid 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)
return load_json(filename)
except HomeAssistantError:
pass
return {}
33 changes: 4 additions & 29 deletions homeassistant/components/fan/insteon_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
"""
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 +33,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,11 +88,11 @@ 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(
if not save_json(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When will save json return False? It seems to raise an error in two cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, i looked at the new save_json and saw it returns False at the end, but didn't question the code itself.

There were several components with some custom error logging if save failed, guess we can just get rid of all those occurrences.

Copy link
Member

@MartinHjelmare MartinHjelmare Nov 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, since @balloob thought it better to blow up in that case when reviewing #10216 .

Edit: Although, then when will the save_json function ever return False? Maybe that should just be removed?

hass.config.path(INSTEON_LOCAL_FANS_CONF),
conf_fans):
_LOGGER.error("Failed to save configuration file")
Expand All @@ -101,31 +101,6 @@ def setup_fan(device_id, name, insteonhub, hass, add_devices_callback):
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
48 changes: 7 additions & 41 deletions homeassistant/components/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,15 @@
import voluptuous as vol
# from voluptuous.humanize import humanize_error

from homeassistant.components.http import HomeAssistantView
from homeassistant.const import (HTTP_INTERNAL_SERVER_ERROR,
HTTP_BAD_REQUEST)
from homeassistant.core import callback
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.util.json import load_json, save_json

from homeassistant.const import (HTTP_INTERNAL_SERVER_ERROR,
HTTP_BAD_REQUEST)

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -173,37 +170,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 +210,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 +271,7 @@ def post(self, request):

CONFIG_FILE[ATTR_DEVICES][name] = data

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

Expand Down
34 changes: 5 additions & 29 deletions homeassistant/components/light/insteon_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from homeassistant.components.light import (
ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light)
import homeassistant.util as util
from homeassistant.util.json import load_json, save_json


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

conf_lights = config_from_file(hass.config.path(INSTEON_LOCAL_LIGHTS_CONF))
conf_lights = load_json(hass.config.path(INSTEON_LOCAL_LIGHTS_CONF))
if conf_lights:
for device_id in conf_lights:
setup_light(device_id, conf_lights[device_id], insteonhub, hass,
Expand Down Expand Up @@ -85,44 +87,18 @@ def setup_light(device_id, name, insteonhub, hass, add_devices_callback):
configurator.request_done(request_id)
_LOGGER.debug("Device configuration done")

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

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

device = insteonhub.dimmer(device_id)
add_devices_callback([InsteonLocalDimmerDevice(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 InsteonLocalDimmerDevice(Light):
"""An abstract Class for an Insteon node."""

Expand Down
Loading