Permalink
Browse files

Remove pyaml and move to ruamel only for yaml

Why:

 * using two libraries for yaml is annoying.
 * 0.4 accidentally used pyyaml incompatible with homeassistant so
   lets avoid that.

This change addreses the need by:

 * move all code to use ruamel yaml.
 * made it possible eventually to control what version of yaml
   ruamel will use if ever needed.
  • Loading branch information...
maxandersen committed Feb 7, 2019
1 parent 5d93c0c commit df9f8c23fa9993f16c735159634f29d2a50e1a43
@@ -6,7 +6,9 @@

import click
import homeassistant_cli.const as const
import homeassistant_cli.yaml as yaml
from requests import Session # noqa: ignore
from ruamel.yaml import YAML
import zeroconf

_LOGGING = logging.getLogger(__name__)
@@ -165,3 +167,16 @@ def auto_output(self, auto_output: str) -> str:
_LOGGING.debug("Setting auto-output to: %s", auto_output)
self.output = auto_output
return self.output

def yaml(self) -> YAML:
"""Create default yaml parser."""
if self:
return yaml.yaml()

def yamlload(self, source: str) -> Any:
"""Utility used to load yaml."""
return self.yaml().load(source)

def yamldump(self, source: Any) -> str:
"""Dump dictionary to yaml string."""
return cast(str, yaml.dumpyaml(self.yaml(), source))
@@ -8,8 +8,9 @@

from homeassistant_cli.config import Configuration
import homeassistant_cli.const as const
import homeassistant_cli.yaml as yaml
from ruamel.yaml import YAML
from tabulate import tabulate
import yaml

_LOGGING = logging.getLogger(__name__)

@@ -47,6 +48,7 @@ def to_tuples(entry: str) -> List[Tuple[str, str]]:
def raw_format_output(
output: str,
data: List[Dict[str, Any]],
yamlparser: YAML,
columns: Optional[List] = None,
no_headers: bool = False,
table_format: str = 'plain',
@@ -67,7 +69,7 @@ def raw_format_output(
return str(data)
elif output == 'yaml':
try:
return cast(str, yaml.safe_dump(data, default_flow_style=False))
return cast(str, yaml.dumpyaml(yamlparser, data))
except ValueError:
return str(data)
elif output == 'table':
@@ -124,6 +126,7 @@ def format_output(
return raw_format_output(
ctx.output,
data,
ctx.yaml(),
columns,
ctx.no_headers,
ctx.table_format,
@@ -11,7 +11,6 @@
import homeassistant_cli.const as const
import homeassistant_cli.helper as helper
import homeassistant_cli.remote as api
import yaml

_LOGGING = logging.getLogger(__name__)

@@ -136,16 +135,20 @@ def edit(ctx: Configuration, entity, newstate, attributes, merge, json):
else:
existing = api.get_state(ctx, entity)
if existing:
existingraw = helper.raw_format_output(ctx.output, [existing])[0]
existingraw = helper.raw_format_output(
ctx.output, [existing], ctx.yaml()
)[0]
else:
existingraw = helper.raw_format_output(ctx.output, [{}])[0]
existingraw = helper.raw_format_output(
ctx.output, [{}], ctx.yaml()
)[0]

new = click.edit(existingraw, extension='.{}'.format(ctx.output))

if new is not None:
ctx.echo("Updating '%s'", entity)
if ctx.output == 'yaml':
wanted_state = yaml.load(new)
wanted_state = ctx.yamlload(new)
if ctx.output == 'json':
wanted_state = json_.loads(new)

@@ -8,7 +8,6 @@
from homeassistant_cli.config import Configuration
from homeassistant_cli.helper import raw_format_output
import homeassistant_cli.remote as api
import yaml

_LOGGING = logging.getLogger(__name__)

@@ -35,13 +34,13 @@ def fire(ctx: Configuration, event, json):
click.echo("Fire {}".format(event))
response = api.fire_event(ctx, event, json)
else:
existing = raw_format_output(ctx.output, {}) # type: ignore
existing = raw_format_output(ctx.output, [{}], ctx.yaml())
new = click.edit(existing, extension='.{}'.format(ctx.output))

if new:
click.echo("Fire {}".format(event))
if ctx.output == 'yaml':
data = yaml.load(new)
data = ctx.yamlload(new)
else:
data = json_.loads(new)

@@ -51,4 +50,4 @@ def fire(ctx: Configuration, event, json):
return

if response:
ctx.echo(raw_format_output(ctx.output, response)) # type: ignore
ctx.echo(raw_format_output(ctx.output, [response], ctx.yaml()))
@@ -8,7 +8,6 @@
from homeassistant_cli.config import Configuration
import homeassistant_cli.remote as api
from jinja2 import Environment, FileSystemLoader
import yaml

_LOGGING = logging.getLogger(__name__)

@@ -49,7 +48,7 @@ def cli(ctx: Configuration, template, datafile, local: bool) -> None:
"""
variables = {} # type: Dict[str, Any]
if datafile:
variables = yaml.load(datafile)
variables = ctx.yamlload(datafile)

templatestr = template.read()

@@ -0,0 +1,34 @@
"""Yaml utility for hass-cli."""

from typing import Any, Optional, cast

from ruamel.yaml import YAML
from ruamel.yaml.compat import StringIO


def yaml() -> YAML:
""""Return default YAML parser."""
yamlp = YAML(typ='rt')
yamlp.preserve_quotes = True
yamlp.default_flow_style = False
return yamlp


def loadyaml(yamlp: YAML, source: str) -> Any:
"""Load yaml."""
return yamlp.load(source)


def dumpyaml(
yamlp: YAML, data: Any, stream: Any = None, **kw: Any
) -> Optional[str]:
"""Dump yaml to string."""

inefficient = False
if stream is None:
inefficient = True
stream = StringIO()
yamlp.dump(data, stream, **kw)
if inefficient:
return cast(str, stream.getvalue())
return None
@@ -62,14 +62,15 @@ def find_version(*file_paths):

REQUIRES = [
'requests==2.21.0',
'pyyaml>=4.2b1',
'netdisco==2.3.0',
'click==7.0',
'click-log==0.3.2',
'tabulate==0.8.3',
'jsonpath-rw==1.4.0',
'jinja2>=2.10',
'dateparser==0.7.0',
'regex==2019.01.24',
'ruamel.yaml==0.15.85',
]

# Should be as close to Home Assistant dev/master as possible
@@ -5,8 +5,8 @@
from click.testing import CliRunner
import homeassistant_cli.cli as cli
from homeassistant_cli.exceptions import HomeAssistantCliError
import homeassistant_cli.yaml as yaml
import requests_mock
import yaml

VALID_INFO = {
"base_url": "http://192.168.1.156:8123",
@@ -84,4 +84,4 @@ def test_info_yaml() -> None:
cli.cli, ['--output=yaml', 'info'], catch_exceptions=False
)
assert result.exit_code == 0
assert [VALID_INFO] == yaml.load(result.output)
assert [VALID_INFO] == yaml.loadyaml(yaml.yaml(), result.output)

0 comments on commit df9f8c2

Please sign in to comment.