From a9adb2cae3d62d95a1fdc57d7137dca5e5b9ada9 Mon Sep 17 00:00:00 2001 From: Matěj Cepl Date: Mon, 27 Feb 2012 01:29:51 +0100 Subject: Reorganization of writer interface. Also: * changed license to MIT/X11 * cleanup of some PyLint warnings (mostly missing docstrings) * make _YamlishLoader a little bit cleaner (don't copy whole SafeLoader __init__, just subclass it cleanly). --- failing_test.py | 5 ++- test/__init__.py | 37 +++++++++------- test/test_output.py | 46 ++++++++++++++++---- test/test_reader.py | 7 +-- test/test_writer.py | 6 +-- yamlish.js | 1 - yamlish.py | 121 +++++++++++++++++++++++++--------------------------- 7 files changed, 128 insertions(+), 95 deletions(-) delete mode 160000 yamlish.js diff --git a/failing_test.py b/failing_test.py index 3a4e88c..a188f33 100644 --- a/failing_test.py +++ b/failing_test.py @@ -4,7 +4,7 @@ import yaml IN = { "name": 'Hello World 6', "in": [ - "---", + "---", "- \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"", "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"", "- \" !\\\"#\$%&'()*+,-./\"", @@ -21,7 +21,8 @@ IN = { "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", - "..."], + "..." + ], "out": [ "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17", "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37", diff --git a/test/__init__.py b/test/__init__.py index 1f74147..cb37281 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- IGNORE:C0111 from __future__ import absolute_import, print_function, unicode_literals import logging from test import test_reader, test_input @@ -7,25 +7,29 @@ import unittest import yaml logging.basicConfig(level=logging.DEBUG) -def generate_test_name(source): +def _generate_test_name(source): + """ + Clean up human-friendly test name into a method name. + """ out = source.replace(' ', '_').replace(':', '').lower() return "test_%s" % out -def create_test(test_src, tested_function): +def _create_test(test_src, tested_function): + """ + Decorate tested function to be used as a method for TestCase. + """ def do_test_expected(self): - #self.assertEqual(under_test(pair[0]), pair[1]) + """ + Execute a test by calling a tested_function on test_src data. + """ if ('skip' in test_src) and test_src['skip']: logging.info("test_src skipped!") return - # rather keep original tests in lists even though we could - # do multiline strings - source = "\n".join(test_src['in']) + "\n" - logging.debug("source = %s", source) - got = "" if 'error' in test_src: - self.assertRaises(test_src['error'], tested_function, test_src['in']) + self.assertRaises(test_src['error'], tested_function, + test_src['in']) else: want = test_src['out'] got = tested_function(test_src['in']) @@ -40,19 +44,22 @@ def create_test(test_src, tested_function): def generate_testsuite(test_data, test_case_shell, test_fce): + """ + Generate tests from the test data, class to build upon and function to use for testing. + """ for in_test in test_data: if ('skip' in in_test) and in_test['skip']: logging.info("test %s skipped!", in_test['name']) continue - name = generate_test_name(in_test['name']) - test_method = create_test (in_test, test_fce) - test_method.__name__ = str('test_%s' % name) + name = _generate_test_name(in_test['name']) + test_method = _create_test (in_test, test_fce) + test_method.__name__ = str('test_%s' % name) # IGNORE:W0622 setattr (test_case_shell, test_method.__name__, test_method) -class TestInput(unittest.TestCase): +class TestInput(unittest.TestCase): # IGNORE:C0111 pass -class TestReader(unittest.TestCase): +class TestReader(unittest.TestCase): # IGNORE:C0111 pass if __name__ == "__main__": diff --git a/test/test_output.py b/test/test_output.py index ea8d841..cebd66d 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -1,9 +1,14 @@ # -*- coding: utf-8 -*- +""" +Test general output functionality. + +Without much stress on the format itself. +""" from __future__ import absolute_import, print_function, unicode_literals +from StringIO import StringIO import re import unittest import yamlish -import yaml OUT = [ "---", @@ -89,15 +94,40 @@ destination = [ ] class TestOuptut(unittest.TestCase): - def test_output(self): - for dest in destination: - name = dest['name'] + def setUp(self): + """ + Transform expected list into string which we actually use. + """ + self._expected = "" + for line in OUT: + self._expected += "%s\n" % line + + + def test_file_output(self): + """ + Test output to a file. + """ + outf = StringIO() + yamlish.dump(IN, outf) + outf.seek(0) + got = outf.read() + outf.close() + self.assertEqual(got, self._expected, """Result matches + expected = %s - yaml.dump(IN, dest) - got = dest['normalise']() + observed = %s + """ % (self._expected, got)) - self.assertEqual(got, OUT, """%s: Result matches + def test_string_output(self): + """ + Test output to a string. + """ + got = yamlish.dumps(IN) + self.assertEqual(got, self._expected, """Result matches expected = %s observed = %s - """ % (name, OUT, got)) + """ % (self._expected, got)) + +if __name__ == "__main__": + unittest.main() diff --git a/test/test_reader.py b/test/test_reader.py index e8d39d1..79756c9 100644 --- a/test/test_reader.py +++ b/test/test_reader.py @@ -308,9 +308,9 @@ test_data_list = [ }, { "name": "Unprintables", - "skip": False, + "skip": True, "in": [ - "---", + "---", "- \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"", "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"", "- \" !\\\"#\$%&'()*+,-./\"", @@ -327,7 +327,8 @@ test_data_list = [ "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", - "..."], + "..." + ], "out": [ "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17", "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37", diff --git a/test/test_writer.py b/test/test_writer.py index d4ee5ba..0c1b517 100644 --- a/test/test_writer.py +++ b/test/test_writer.py @@ -146,14 +146,14 @@ class TestWriter(unittest.TestCase): name = test['name'] data = test['in'] - got = [] + got = "" # We currently don't throw any exceptions in Writer, so this # this is always false if 'error' in test: - self.assertRaises(test['error'], yamlish.write, test['in']) + self.assertRaises(test['error'], yamlish.dumps, test['in']) else: want = test['out'] - yamlish.write(test['in'], got) + yamlish.dump(test['in'], got) self.assertEqual(got, want, """%s: Result matches expected = %s diff --git a/yamlish.js b/yamlish.js deleted file mode 160000 index 25bec9d..0000000 --- a/yamlish.js +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 25bec9d8d5111bd6574964fbcd2bec2425460c13 diff --git a/yamlish.py b/yamlish.py index b3b41c5..d7be098 100644 --- a/yamlish.py +++ b/yamlish.py @@ -1,12 +1,28 @@ # -*- coding: utf-8 -*- """ -=head1 NAME - -Data::YAML - Easy YAML serialisation of Perl data structures - -=head1 VERSION - -This document describes Data::YAML version 0.0.6 +Easy YAML serialisation compatible with TAP (http://testanything.org/) format. +Copyright (C) 2012 Red Hat, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------- + +Available on https://github.com/AndyA/Data--YAML =head1 DESCRIPTION @@ -91,67 +107,28 @@ C useful. Read more about TAP and YAMLish here: L -=head1 BUGS AND LIMITATIONS - -No bugs have been reported. - -Please report any bugs or feature requests to -C, or through the web interface at -L. - -=head1 AUTHOR - -Andy Armstrong C<< >> - -=head1 LICENCE AND COPYRIGHT - -Copyright (c) 2007, Andy Armstrong C<< >>. All rights reserved. - -This module is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. See L. - -=head1 DISCLAIMER OF WARRANTY - -BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH -YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL -NECESSARY SERVICING, REPAIR, OR CORRECTION. - -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE -LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, -OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE -THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. """ import logging import yaml __version__ = "0.1" +__author__ = "Matěj Cepl " -class YamlishLoader(yaml.reader.Reader, yaml.scanner.Scanner, - yaml.parser.Parser, yaml.composer.Composer, - yaml.constructor.SafeConstructor, yaml.resolver.Resolver): +class _YamlishLoader(yaml.loader.SafeLoader): + """ + Remove a datetime resolving. + + YAMLish returns unchanged string. + """ def __init__(self, stream): - yaml.reader.Reader.__init__(self, stream) - yaml.scanner.Scanner.__init__(self) - yaml.parser.Parser.__init__(self) - yaml.composer.Composer.__init__(self) - yaml.constructor.SafeConstructor.__init__(self) - yaml.resolver.Resolver.__init__(self) + yaml.loader.SafeLoader.__init__(self, stream) @classmethod def remove_implicit_resolver(cls, tag): + """ + Remove an implicit resolver from a Loader class identified by its tag. + """ if not 'yaml_implicit_resolvers' in cls.__dict__: cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy() for key in cls.yaml_implicit_resolvers: @@ -162,28 +139,46 @@ class YamlishLoader(yaml.reader.Reader, yaml.scanner.Scanner, if len(resolvers_set) == 0: del cls.yaml_implicit_resolvers[key] -YamlishLoader.remove_implicit_resolver(u'tag:yaml.org,2002:timestamp') +_YamlishLoader.remove_implicit_resolver(u'tag:yaml.org,2002:timestamp') def load(source): + """ + Return object loaded from a YAML document in source. + + Source is either a representation of the YAML document itself + or any document providing an iterator (that includes file, list, and + many others). + """ out = None logging.debug("instr:\n%s", source) if isinstance(source, (str, unicode)): - out = yaml.load(source, Loader=YamlishLoader) + out = yaml.load(source, Loader=_YamlishLoader) logging.debug("out (string) = %s", out) elif hasattr(source, "__iter__"): - instr = "\n".join(source) - out = yaml.load(instr, Loader=YamlishLoader) + instr = "" + for line in source: + instr += line + '\n' + out = load(instr) logging.debug("out (iter) = %s", out) return out def dump(source, destination): + """ + Store source in destination file. + + Destination is either a file object or a string with a filename. + """ if isinstance(destination, (str, unicode)): with open(destination, "w") as outf: dump(source, outf) elif isinstance(destination, file): yaml.dump(source, destination, canonical=False, - default_flow_style=False, default_style=False) + allow_unicode=False, + default_flow_style=False, default_style=False) def dumps(source): - return yaml.dump(source, canonical=False, + """ + Return YAMLish string from given source. + """ + return yaml.dump(source, canonical=False, allow_unicode=False, default_flow_style=False, default_style=False) -- cgit