From a4589bbc4875f99b8ebb66495efe1f9a996ed474 Mon Sep 17 00:00:00 2001 From: Andre Fonseca Date: Tue, 18 Oct 2016 15:59:46 -0200 Subject: [PATCH 1/6] Adding a new task for dev setup step --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 500d48a2..a7ef63d1 100644 --- a/Makefile +++ b/Makefile @@ -27,4 +27,8 @@ man: head -1 rows.1.txt > rows.1 txt2man rows.1.txt | egrep -v '^\.TH' >> rows.1 -.PHONY: test clean lint lint-tests install uninstall man +dev-setup: + pip install --editable .[all] + pip install -r requirements-development.txt + +.PHONY: test clean lint lint-tests install uninstall man dev-setup From 8f13f7c2c0d2f5ce180f3a6145f34a60080ecfa3 Mon Sep 17 00:00:00 2001 From: Andre Fonseca Date: Tue, 18 Oct 2016 16:00:27 -0200 Subject: [PATCH 2/6] Fixing Typo and Pep8 --- rows/plugins/plugin_json.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/rows/plugins/plugin_json.py b/rows/plugins/plugin_json.py index 795b990e..5dbf14d7 100644 --- a/rows/plugins/plugin_json.py +++ b/rows/plugins/plugin_json.py @@ -17,10 +17,7 @@ from __future__ import unicode_literals -import datetime -import decimal import json - import six from rows import fields From 0f92fbf0a2e3fe6175b8afd5dcf9814b9d49b00b Mon Sep 17 00:00:00 2001 From: Andre Fonseca Date: Tue, 18 Oct 2016 16:00:48 -0200 Subject: [PATCH 3/6] Adding a new dependency for project. PyYaml --- setup.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/setup.py b/setup.py index 9544aac8..96918132 100644 --- a/setup.py +++ b/setup.py @@ -21,15 +21,16 @@ EXTRA_REQUIREMENTS = { - 'csv': ['unicodecsv'], - 'cli': ['click', 'requests'], - 'html': ['lxml'], # apt: libxslt-dev libxml2-dev - 'ods': ['lxml'], - 'parquet': ['parquet>=1.1'], - 'xls': ['xlrd', 'xlwt'], - 'xlsx': ['openpyxl'], - 'xpath': ['lxml'], - 'detect': ['file-magic'], } + 'csv': ['unicodecsv'], + 'yaml': ['pyyaml'], + 'cli': ['click', 'requests'], + 'html': ['lxml'], + 'ods': ['lxml'], + 'parquet': ['parquet>=1.1'], + 'xls': ['xlrd', 'xlwt'], + 'xlsx': ['openpyxl'], + 'xpath': ['lxml'], + 'detect': ['file-magic'], } EXTRA_REQUIREMENTS['all'] = sum(EXTRA_REQUIREMENTS.values(), []) INSTALL_REQUIREMENTS = ['six'] + EXTRA_REQUIREMENTS['csv'] LONG_DESCRIPTION = ''' @@ -56,12 +57,12 @@ extras_require=EXTRA_REQUIREMENTS, keywords=['tabular', 'table', 'csv', 'xls', 'xlsx', 'xpath', 'sqlite', 'html', 'rows', 'data', 'opendata'], - entry_points = { + entry_points={ 'console_scripts': [ 'rows = rows.cli:cli', ], }, - classifiers = [ + classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', @@ -75,5 +76,4 @@ 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Text Processing :: Markup :: HTML', 'Topic :: Utilities', - ] -) + ]) From 9a88723913785be0fec930f1b86d2d1f71c56275 Mon Sep 17 00:00:00 2001 From: Andre Fonseca Date: Tue, 18 Oct 2016 16:48:33 -0200 Subject: [PATCH 4/6] Adding a fixture yaml file --- tests/data/all-field-types.yaml | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/data/all-field-types.yaml diff --git a/tests/data/all-field-types.yaml b/tests/data/all-field-types.yaml new file mode 100644 index 00000000..0dadcce8 --- /dev/null +++ b/tests/data/all-field-types.yaml @@ -0,0 +1,57 @@ +--- +- float_column: 3.141592 + decimal_column: 3.141592 + bool_column: 'True' + integer_column: 1 + date_column: '2015-01-01' + datetime_column: '2015-08-18T15:10:00' + percent_column: 1% + unicode_column: Álvaro +- float_column: 1.234 + decimal_column: 1.234 + bool_column: 'False' + integer_column: 2 + date_column: '1999-02-03' + datetime_column: '1999-02-03T00:01:02' + percent_column: 11.69% + unicode_column: àáãâä¹²³ +- float_column: 4.56 + decimal_column: 4.56 + bool_column: true + integer_column: 3 + date_column: '2050-01-02' + datetime_column: '2050-01-02T23:45:31' + percent_column: 12% + unicode_column: éèẽêë +- float_column: 7.89 + decimal_column: 7.89 + bool_column: false + integer_column: 4 + date_column: '2015-08-18' + datetime_column: '2015-08-18T22:21:33' + percent_column: 13.64% + unicode_column: "~~~~" +- float_column: 9.87 + decimal_column: 9.87 + bool_column: 'yes' + integer_column: 5 + date_column: '2015-03-04' + datetime_column: '2015-03-04T16:00:01' + percent_column: 13.14% + unicode_column: álvaro +- float_column: 1.2345 + decimal_column: 1.2345 + bool_column: 'no' + integer_column: 6 + date_column: '2015-05-06' + datetime_column: '2015-05-06T12:01:02' + percent_column: 2% + unicode_column: test +- float_column: '' + decimal_column: "-" + bool_column: 'null' + integer_column: nil + date_column: none + datetime_column: n/a + percent_column: 'null' + unicode_column: '' From 433ecb73da139d16f3cbd0ea64d243a3b0808ad8 Mon Sep 17 00:00:00 2001 From: Andre Fonseca Date: Tue, 18 Oct 2016 17:12:54 -0200 Subject: [PATCH 5/6] First version of yaml plugin --- rows/plugins/plugin_yaml.py | 85 ++++++++++++++ tests/tests_plugin_yaml.py | 213 ++++++++++++++++++++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 rows/plugins/plugin_yaml.py create mode 100644 tests/tests_plugin_yaml.py diff --git a/rows/plugins/plugin_yaml.py b/rows/plugins/plugin_yaml.py new file mode 100644 index 00000000..dd5c394a --- /dev/null +++ b/rows/plugins/plugin_yaml.py @@ -0,0 +1,85 @@ +# coding: utf-8 + +# Copyright 2014-2016 Álvaro Justen +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals + +import six +import yaml + +from rows import fields +from rows.plugins.utils import (create_table, export_data, + get_filename_and_fobj, prepare_to_export) + + +def import_from_yaml(filename_or_fobj, encoding='utf-8', *args, **kwargs): + '''Import a YAML file or file-like object into a `rows.Table` + + If a file-like object is provided it MUST be open in text (non-binary) mode + on Python 3 and could be open in both binary or text mode on Python 2. + ''' + + filename, fobj = get_filename_and_fobj(filename_or_fobj) + + yaml_obj = yaml.load(fobj) + field_names = list(yaml_obj[0].keys()) + table_rows = [[item[key] for key in field_names] for item in yaml_obj] + + meta = { + 'imported_from': 'yaml', + 'filename': filename, + 'encoding': encoding + } + return create_table([field_names] + table_rows, meta=meta, *args, **kwargs) + + +def _convert(value, field_type, *args, **kwargs): + if value is None or field_type in ( + fields.BinaryField, + fields.BoolField, + fields.FloatField, + fields.IntegerField, + fields.JSONField, + fields.TextField,): + return value + else: + return field_type.serialize(value, *args, **kwargs) + + +def export_to_yaml(table, filename_or_fobj=None, encoding='utf-8', indent=None, + *args, **kwargs): + '''Export a `rows.Table` to a YAML file or file-like object + ''' + + all_fields = table.fields + prepared_table = prepare_to_export(table, *args, **kwargs) + field_names = next(prepared_table) + data = [{field_name: _convert(value, + all_fields[field_name], + *args, + **kwargs) + for field_name, value in zip(field_names, row)} + for row in prepared_table] + + result = yaml.dump(data, indent=indent) + if type(result) is six.text_type: + result = result.encode(encoding) + + if indent is not None: + # clean up empty spaces at the end of lines + result = b'\n'.join(line.rstrip() for line in result.splitlines()) + + return export_data(filename_or_fobj, result, mode='wb') diff --git a/tests/tests_plugin_yaml.py b/tests/tests_plugin_yaml.py new file mode 100644 index 00000000..0940fdfa --- /dev/null +++ b/tests/tests_plugin_yaml.py @@ -0,0 +1,213 @@ +# coding: utf-8 + +# Copyright 2014-2016 Álvaro Justen +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals + +import itertools +import yaml +import tempfile +import unittest + +from collections import Counter +from collections import OrderedDict +from collections import defaultdict +from textwrap import dedent + +import six +import mock + +import rows +import tests.utils as utils + + +class PluginYamlTestCase(utils.RowsTestMixIn, unittest.TestCase): + + plugin_name = 'yaml' + file_extension = 'yaml' + filename = 'tests/data/all-field-types.yaml' + encoding = 'utf-8' + assert_meta_encoding = True + + def test_imports(self): + self.assertIs(rows.import_from_yaml, + rows.plugins.plugin_yaml.import_from_yaml) + self.assertIs(rows.export_to_yaml, + rows.plugins.plugin_yaml.export_to_yaml) + + @mock.patch('rows.plugins.plugin_yaml.create_table') + def test_import_from_yaml_uses_create_table(self, mocked_create_table): + mocked_create_table.return_value = 42 + kwargs = {'some_key': 123, 'other': 456, } + result = rows.import_from_yaml(self.filename, encoding=self.encoding, + **kwargs) + self.assertTrue(mocked_create_table.called) + self.assertEqual(mocked_create_table.call_count, 1) + self.assertEqual(result, 42) + + call = mocked_create_table.call_args + kwargs['meta'] = {'imported_from': 'yaml', + 'filename': self.filename, + 'encoding': self.encoding,} + self.assertEqual(call[1], kwargs) + + @mock.patch('rows.plugins.plugin_json.create_table') + def test_import_from_json_retrieve_desired_data(self, mocked_create_table): + mocked_create_table.return_value = 42 + + # import using filename + table_1 = rows.import_from_json(self.filename) + call_args = mocked_create_table.call_args_list[0] + self.assert_create_table_data(call_args, field_ordering=False) + + # import using fobj + with open(self.filename) as fobj: + table_2 = rows.import_from_json(fobj) + call_args = mocked_create_table.call_args_list[1] + self.assert_create_table_data(call_args, field_ordering=False) + + @mock.patch('rows.plugins.plugin_json.create_table') + def test_import_from_json_uses_create_table(self, mocked_create_table): + mocked_create_table.return_value = 42 + kwargs = {'some_key': 123, 'other': 456, } + encoding = 'iso-8859-15' + result = rows.import_from_json(self.filename, encoding=encoding, + **kwargs) + self.assertTrue(mocked_create_table.called) + self.assertEqual(mocked_create_table.call_count, 1) + self.assertEqual(result, 42) + + call = mocked_create_table.call_args + kwargs['meta'] = {'imported_from': 'json', + 'filename': self.filename, + 'encoding': encoding,} + self.assertEqual(call[1], kwargs) + + @mock.patch('rows.plugins.plugin_json.prepare_to_export') + def test_export_to_json_uses_prepare_to_export(self, + mocked_prepare_to_export): + temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') + self.files_to_delete.append(temp.name) + kwargs = {'test': 123, 'parameter': 3.14, } + mocked_prepare_to_export.return_value = \ + iter([utils.table.fields.keys()]) + + rows.export_to_json(utils.table, temp.name, **kwargs) + self.assertTrue(mocked_prepare_to_export.called) + self.assertEqual(mocked_prepare_to_export.call_count, 1) + + call = mocked_prepare_to_export.call_args + self.assertEqual(call[0], (utils.table, )) + self.assertEqual(call[1], kwargs) + + @mock.patch('rows.plugins.plugin_json.export_data') + def test_export_to_json_uses_export_data(self, mocked_export_data): + temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') + self.files_to_delete.append(temp.name) + kwargs = {'test': 123, 'parameter': 3.14, } + mocked_export_data.return_value = 42 + + result = rows.export_to_json(utils.table, temp.name, **kwargs) + self.assertTrue(mocked_export_data.called) + self.assertEqual(mocked_export_data.call_count, 1) + self.assertEqual(result, 42) + + call = mocked_export_data.call_args + self.assertEqual(call[0][0], temp.name) + self.assertEqual(call[1], {'mode': 'wb'}) + + def test_export_to_json_filename(self): + # TODO: may test file contents + temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') + self.files_to_delete.append(temp.name) + rows.export_to_json(utils.table, temp.name) + table = rows.import_from_json(temp.name) + self.assert_table_equal(table, utils.table) + + def test_export_to_json_fobj(self): + # TODO: may test with codecs.open passing an encoding + # TODO: may test file contents + temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') + self.files_to_delete.append(temp.name) + rows.export_to_json(utils.table, temp.file) + + table = rows.import_from_json(temp.name) + self.assert_table_equal(table, utils.table) + + def test_export_to_json_filename_save_data_in_correct_format(self): + temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') + self.files_to_delete.append(temp.name) + + rows.export_to_json(utils.table, temp.name) + + with open(temp.name) as fobj: + imported_json = json.load(fobj) + + COLUMN_TYPE = { + 'float_column': float, + 'decimal_column': float, + 'bool_column': bool, + 'integer_column': int, + 'date_column': six.text_type, + 'datetime_column': six.text_type, + 'percent_column': six.text_type, + 'unicode_column': six.text_type, + } + field_types = defaultdict(list) + for row in imported_json: + for field_name, value in row.items(): + field_types[field_name].append(type(value)) + # We test if the JSON was created serializing all the fields correctly + # (some as native JSON values, like int and float) and others needed to + # be serialized, like date, datetime etc. + for field_name, value_types in field_types.items(): + if field_name != 'unicode_column': + self.assertEqual(Counter(value_types), + Counter({type(None): 1, + COLUMN_TYPE[field_name]: 6})) + else: + self.assertEqual(Counter(value_types), + Counter({COLUMN_TYPE[field_name]: 7})) + + def test_export_to_json_indent(self): + temp = tempfile.NamedTemporaryFile(delete=False, mode='rb+') + self.files_to_delete.append(temp.name) + + table = rows.Table(fields=utils.table.fields) + table.append(utils.table[0]._asdict()) + rows.export_to_json(table, temp.name, indent=2) + + temp.file.seek(0) + result = temp.file.read().strip().replace(b'\r\n', b'\n').splitlines() + self.assertEqual(result[0], b'[') + self.assertEqual(result[1], b' {') + for line in result[2:-2]: + self.assertTrue(line.startswith(b' ')) + self.assertEqual(result[-2], b' }') + self.assertEqual(result[-1], b']') + + def test_issue_168(self): + temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') + filename = '{}.{}'.format(temp.name, self.file_extension) + self.files_to_delete.append(filename) + + table = rows.Table(fields= + OrderedDict([('jsoncolumn', rows.fields.JSONField)])) + table.append({'jsoncolumn': '{"python": 42}'}) + rows.export_to_json(table, filename) + + table2 = rows.import_from_json(filename) + self.assert_table_equal(table, table2) From 79e77ae18a0680e7485b06ce30722d1c38a915ff Mon Sep 17 00:00:00 2001 From: Andre Fonseca Date: Tue, 18 Oct 2016 22:31:19 -0200 Subject: [PATCH 6/6] Fixing problems with new plugin. Writing tests for it Adding a new task in Makefile. --- Makefile | 5 ++- rows/__init__.py | 3 ++ rows/plugins/__init__.py | 1 + tests/tests_plugin_yaml.py | 84 ++++++++++++-------------------------- 4 files changed, 34 insertions(+), 59 deletions(-) diff --git a/Makefile b/Makefile index a7ef63d1..644fc68a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ test: tox +tests_nose: + nosetests -dsv --with-yanc --with-coverage --cover-package rows tests/*.py + clean: find -regex '.*\.pyc' -exec rm {} \; find -regex '.*~' -exec rm {} \; @@ -31,4 +34,4 @@ dev-setup: pip install --editable .[all] pip install -r requirements-development.txt -.PHONY: test clean lint lint-tests install uninstall man dev-setup +.PHONY: test clean lint lint-tests install uninstall man dev-setup tests_nose diff --git a/rows/__init__.py b/rows/__init__.py index 171dbf93..06438103 100644 --- a/rows/__init__.py +++ b/rows/__init__.py @@ -27,6 +27,9 @@ # Don't have dependencies or dependencies installed on `install_requires` +import_from_yaml = plugins.yaml.import_from_yaml +export_to_yaml = plugins.yaml.export_to_yaml + import_from_json = plugins.json.import_from_json export_to_json = plugins.json.export_to_json diff --git a/rows/plugins/__init__.py b/rows/plugins/__init__.py index 3a2a307c..40df5f01 100644 --- a/rows/plugins/__init__.py +++ b/rows/plugins/__init__.py @@ -16,6 +16,7 @@ # along with this program. If not, see . from . import plugin_json as json +from . import plugin_yaml as yaml from . import dicts as dicts from . import plugin_csv as csv from . import txt as txt diff --git a/tests/tests_plugin_yaml.py b/tests/tests_plugin_yaml.py index 0940fdfa..e593ec89 100644 --- a/tests/tests_plugin_yaml.py +++ b/tests/tests_plugin_yaml.py @@ -17,15 +17,13 @@ from __future__ import unicode_literals -import itertools -import yaml -import tempfile import unittest +import tempfile +import yaml from collections import Counter from collections import OrderedDict from collections import defaultdict -from textwrap import dedent import six import mock @@ -64,40 +62,40 @@ def test_import_from_yaml_uses_create_table(self, mocked_create_table): 'encoding': self.encoding,} self.assertEqual(call[1], kwargs) - @mock.patch('rows.plugins.plugin_json.create_table') - def test_import_from_json_retrieve_desired_data(self, mocked_create_table): + @mock.patch('rows.plugins.plugin_yaml.create_table') + def test_import_from_yaml_retrieve_desired_data(self, mocked_create_table): mocked_create_table.return_value = 42 # import using filename - table_1 = rows.import_from_json(self.filename) + table_1 = rows.import_from_yaml(self.filename) call_args = mocked_create_table.call_args_list[0] self.assert_create_table_data(call_args, field_ordering=False) # import using fobj with open(self.filename) as fobj: - table_2 = rows.import_from_json(fobj) + table_2 = rows.import_from_yaml(fobj) call_args = mocked_create_table.call_args_list[1] self.assert_create_table_data(call_args, field_ordering=False) - @mock.patch('rows.plugins.plugin_json.create_table') - def test_import_from_json_uses_create_table(self, mocked_create_table): + @mock.patch('rows.plugins.plugin_yaml.create_table') + def test_import_from_yaml_uses_create_table(self, mocked_create_table): mocked_create_table.return_value = 42 kwargs = {'some_key': 123, 'other': 456, } encoding = 'iso-8859-15' - result = rows.import_from_json(self.filename, encoding=encoding, + result = rows.import_from_yaml(self.filename, encoding=encoding, **kwargs) self.assertTrue(mocked_create_table.called) self.assertEqual(mocked_create_table.call_count, 1) self.assertEqual(result, 42) call = mocked_create_table.call_args - kwargs['meta'] = {'imported_from': 'json', + kwargs['meta'] = {'imported_from': 'yaml', 'filename': self.filename, 'encoding': encoding,} self.assertEqual(call[1], kwargs) - @mock.patch('rows.plugins.plugin_json.prepare_to_export') - def test_export_to_json_uses_prepare_to_export(self, + @mock.patch('rows.plugins.plugin_yaml.prepare_to_export') + def test_export_to_yaml_uses_prepare_to_export(self, mocked_prepare_to_export): temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') self.files_to_delete.append(temp.name) @@ -105,7 +103,7 @@ def test_export_to_json_uses_prepare_to_export(self, mocked_prepare_to_export.return_value = \ iter([utils.table.fields.keys()]) - rows.export_to_json(utils.table, temp.name, **kwargs) + rows.export_to_yaml(utils.table, temp.name, **kwargs) self.assertTrue(mocked_prepare_to_export.called) self.assertEqual(mocked_prepare_to_export.call_count, 1) @@ -113,14 +111,14 @@ def test_export_to_json_uses_prepare_to_export(self, self.assertEqual(call[0], (utils.table, )) self.assertEqual(call[1], kwargs) - @mock.patch('rows.plugins.plugin_json.export_data') - def test_export_to_json_uses_export_data(self, mocked_export_data): + @mock.patch('rows.plugins.plugin_yaml.export_data') + def test_export_to_yaml_uses_export_data(self, mocked_export_data): temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') self.files_to_delete.append(temp.name) kwargs = {'test': 123, 'parameter': 3.14, } mocked_export_data.return_value = 42 - result = rows.export_to_json(utils.table, temp.name, **kwargs) + result = rows.export_to_yaml(utils.table, temp.name, **kwargs) self.assertTrue(mocked_export_data.called) self.assertEqual(mocked_export_data.call_count, 1) self.assertEqual(result, 42) @@ -129,32 +127,32 @@ def test_export_to_json_uses_export_data(self, mocked_export_data): self.assertEqual(call[0][0], temp.name) self.assertEqual(call[1], {'mode': 'wb'}) - def test_export_to_json_filename(self): + def test_export_to_yaml_filename(self): # TODO: may test file contents temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') self.files_to_delete.append(temp.name) - rows.export_to_json(utils.table, temp.name) - table = rows.import_from_json(temp.name) + rows.export_to_yaml(utils.table, temp.name) + table = rows.import_from_yaml(temp.name) self.assert_table_equal(table, utils.table) - def test_export_to_json_fobj(self): + def test_export_to_yaml_fobj(self): # TODO: may test with codecs.open passing an encoding # TODO: may test file contents temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') self.files_to_delete.append(temp.name) - rows.export_to_json(utils.table, temp.file) + rows.export_to_yaml(utils.table, temp.file) - table = rows.import_from_json(temp.name) + table = rows.import_from_yaml(temp.name) self.assert_table_equal(table, utils.table) - def test_export_to_json_filename_save_data_in_correct_format(self): + def test_export_to_yaml_filename_save_data_in_correct_format(self): temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') self.files_to_delete.append(temp.name) - rows.export_to_json(utils.table, temp.name) + rows.export_to_yaml(utils.table, temp.name) with open(temp.name) as fobj: - imported_json = json.load(fobj) + imported_yaml = yaml.load(fobj) COLUMN_TYPE = { 'float_column': float, @@ -167,7 +165,7 @@ def test_export_to_json_filename_save_data_in_correct_format(self): 'unicode_column': six.text_type, } field_types = defaultdict(list) - for row in imported_json: + for row in imported_yaml: for field_name, value in row.items(): field_types[field_name].append(type(value)) # We test if the JSON was created serializing all the fields correctly @@ -181,33 +179,3 @@ def test_export_to_json_filename_save_data_in_correct_format(self): else: self.assertEqual(Counter(value_types), Counter({COLUMN_TYPE[field_name]: 7})) - - def test_export_to_json_indent(self): - temp = tempfile.NamedTemporaryFile(delete=False, mode='rb+') - self.files_to_delete.append(temp.name) - - table = rows.Table(fields=utils.table.fields) - table.append(utils.table[0]._asdict()) - rows.export_to_json(table, temp.name, indent=2) - - temp.file.seek(0) - result = temp.file.read().strip().replace(b'\r\n', b'\n').splitlines() - self.assertEqual(result[0], b'[') - self.assertEqual(result[1], b' {') - for line in result[2:-2]: - self.assertTrue(line.startswith(b' ')) - self.assertEqual(result[-2], b' }') - self.assertEqual(result[-1], b']') - - def test_issue_168(self): - temp = tempfile.NamedTemporaryFile(delete=False, mode='wb') - filename = '{}.{}'.format(temp.name, self.file_extension) - self.files_to_delete.append(filename) - - table = rows.Table(fields= - OrderedDict([('jsoncolumn', rows.fields.JSONField)])) - table.append({'jsoncolumn': '{"python": 42}'}) - rows.export_to_json(table, filename) - - table2 = rows.import_from_json(filename) - self.assert_table_equal(table, table2)