From 0a8daff7bdad7c56bc7b9dc2d6dea6b7259d2827 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Wed, 5 Aug 2015 16:16:54 +1200 Subject: [PATCH] Implement a yaml formatter in cliff This change replaces the cliff-tablib yaml formatter with an internal replacement. It differs from the tablib formatter in the following ways: - always outputs with block formatting rather than the PyYAML default of deciding based on value content - emit_one serialises a simple dict where the column name is the key and the data item is the value (rather than a list of dicts with 'Field' and 'Value' keys) - emit_one preserves column order by printing a single-item dict for each column_name The cliff release which contains this change will need a corresponding cliff-tablib release which removes the yaml formatter from its setup.py entry_points. Change-Id: I691dbab3dee7c5ec28b1083f87ab1f5c051d582b Related-Bug: #1308744 --- cliff/formatters/yaml_format.py | 23 +++++++++++++++ cliff/tests/test_formatters_yaml.py | 45 +++++++++++++++++++++++++++++ doc/source/list_commands.rst | 26 ++++++++++++++++- doc/source/show_commands.rst | 19 +++++++++++- requirements.txt | 1 + setup.cfg | 2 ++ 6 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 cliff/formatters/yaml_format.py create mode 100644 cliff/tests/test_formatters_yaml.py diff --git a/cliff/formatters/yaml_format.py b/cliff/formatters/yaml_format.py new file mode 100644 index 00000000..e6fe17dd --- /dev/null +++ b/cliff/formatters/yaml_format.py @@ -0,0 +1,23 @@ +"""Output formatters using PyYAML. +""" + +import yaml + +from .base import ListFormatter, SingleFormatter + + +class YAMLFormatter(ListFormatter, SingleFormatter): + + def add_argument_group(self, parser): + pass + + def emit_list(self, column_names, data, stdout, parsed_args): + items = [] + for item in data: + items.append(dict(zip(column_names, item))) + yaml.safe_dump(items, stream=stdout, default_flow_style=False) + + def emit_one(self, column_names, data, stdout, parsed_args): + for key, value in zip(column_names, data): + dict_data = {key: value} + yaml.safe_dump(dict_data, stream=stdout, default_flow_style=False) diff --git a/cliff/tests/test_formatters_yaml.py b/cliff/tests/test_formatters_yaml.py new file mode 100644 index 00000000..ef8805fc --- /dev/null +++ b/cliff/tests/test_formatters_yaml.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +from six import StringIO +import yaml + +from cliff.formatters import yaml_format + +import mock + + +def test_yaml_format_one(): + sf = yaml_format.YAMLFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', '"escape me"') + expected = { + 'a': 'A', + 'b': 'B', + 'c': 'C', + 'd': '"escape me"' + } + output = StringIO() + args = mock.Mock() + sf.emit_one(c, d, output, args) + actual = yaml.safe_load(output.getvalue()) + assert expected == actual + + +def test_yaml_format_list(): + sf = yaml_format.YAMLFormatter() + c = ('a', 'b', 'c') + d = ( + ('A1', 'B1', 'C1'), + ('A2', 'B2', 'C2'), + ('A3', 'B3', 'C3') + ) + expected = [ + {'a': 'A1', 'b': 'B1', 'c': 'C1'}, + {'a': 'A2', 'b': 'B2', 'c': 'C2'}, + {'a': 'A3', 'b': 'B3', 'c': 'C3'} + ] + output = StringIO() + args = mock.Mock() + sf.add_argument_group(args) + sf.emit_list(c, d, output, args) + actual = yaml.safe_load(output.getvalue()) + assert expected == actual diff --git a/doc/source/list_commands.rst b/doc/source/list_commands.rst index e2cda76c..b49c651a 100644 --- a/doc/source/list_commands.rst +++ b/doc/source/list_commands.rst @@ -90,10 +90,34 @@ a script. Makefile is 5569 bytes source is 408 bytes +yaml +---- + +The ``yaml`` formatter uses PyYAML_ to produce a YAML sequence of +mappings. + +.. _PyYAML: http://pyyaml.org/ + +:: + + (.venv)$ cliffdemo files -f yaml + - Name: dist + Size: 4096 + - Name: cliffdemo.egg-info + Size: 4096 + - Name: README.rst + Size: 960 + - Name: setup.py + Size: 1807 + - Name: build + Size: 4096 + - Name: cliffdemo + Size: 4096 + Other Formatters ---------------- -Formatters using tablib_ to produce JSON, YAML, and HTML are available +Formatters using tablib_ to produce JSON and HTML are available as part of `cliff-tablib`_. .. _cliff-tablib: https://github.com/dreamhost/cliff-tablib diff --git a/doc/source/show_commands.rst b/doc/source/show_commands.rst index 531045a0..157b1bf5 100644 --- a/doc/source/show_commands.rst +++ b/doc/source/show_commands.rst @@ -83,10 +83,27 @@ value of the field or fields. (.venv)$ echo $SIZE 5916 +yaml +---- + +The ``yaml`` formatter uses PyYAML_ to produce a YAML mapping where +the field name is the key. + +.. _PyYAML: http://pyyaml.org/ + +:: + + (.venv)$ cliffdemo file -f yaml setup.py + Name: setup.py + Size: 1807 + UID: 1000 + GID: 1000 + Modified Time: 1393531476.9587486 + Other Formatters ---------------- -Formatters using tablib_ to produce JSON, YAML, and HTML are available +Formatters using tablib_ to produce JSON and HTML are available as part of `cliff-tablib`_. .. _cliff-tablib: https://github.com/dreamhost/cliff-tablib diff --git a/requirements.txt b/requirements.txt index 67873520..1dda2f08 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ pyparsing>=2.0.1 six>=1.9.0 stevedore>=1.5.0 # Apache-2.0 unicodecsv>=0.8.0 +PyYAML>=3.1.0 diff --git a/setup.cfg b/setup.cfg index ede8b22d..648c6e3f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,11 +30,13 @@ cliff.formatter.list = table = cliff.formatters.table:TableFormatter csv = cliff.formatters.commaseparated:CSVLister value = cliff.formatters.value:ValueFormatter + yaml = cliff.formatters.yaml_format:YAMLFormatter cliff.formatter.show = table = cliff.formatters.table:TableFormatter shell = cliff.formatters.shell:ShellFormatter value = cliff.formatters.value:ValueFormatter + yaml = cliff.formatters.yaml_format:YAMLFormatter cliff.formatter.completion = bash = cliff.complete:CompleteBash