From faacaef0692d880eb861718ebb28e40ecd12c92d Mon Sep 17 00:00:00 2001 From: Josh Ross Date: Sun, 1 Jun 2014 20:24:44 -0700 Subject: [PATCH] Add support for loading yaml strings as unicode. --- CHANGES.rst | 7 +++- charlatan/file_format.py | 17 ++++++++-- charlatan/fixtures_manager.py | 7 ++-- charlatan/tests/data/strings.yaml | 2 ++ charlatan/tests/test_strings.py | 54 +++++++++++++++++++++++++++++++ docs/file-format.rst | 9 ++++++ 6 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 charlatan/tests/data/strings.yaml create mode 100644 charlatan/tests/test_strings.py diff --git a/CHANGES.rst b/CHANGES.rst index bee7a52..63c4712 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,10 +1,15 @@ Changelog for Charlatan ======================= +0.3.5 (unreleased) +------------------ + +- Support loading all strings as unicode + 0.3.4 (2014-01-21) ------------------ -- Fix getting attribute from relationhips +- Fix getting attribute from relationships 0.3.3 (2014-01-18) ------------------ diff --git a/charlatan/file_format.py b/charlatan/file_format.py index ef25f64..365a350 100644 --- a/charlatan/file_format.py +++ b/charlatan/file_format.py @@ -1,8 +1,8 @@ from __future__ import absolute_import -from __future__ import unicode_literals import datetime import yaml +from yaml.constructor import Constructor from charlatan.utils import apply_delta, datetime_to_epoch_timestamp @@ -57,7 +57,19 @@ def relationship_constructor(loader, node): yaml.add_constructor(u'!rel', relationship_constructor) -def load_file(filename): +def configure_output(use_unicode=False): + """Configure output options of the values loaded by pyyaml + + :param boolean use_unicode: Use unicode constructor for loading strings + """ + if use_unicode: + yaml.add_constructor( + u'tag:yaml.org,2002:str', + Constructor.construct_python_unicode, + ) + + +def load_file(filename, unicode_output=False): """Load fixtures definition from file. :param str filename: @@ -69,6 +81,7 @@ def load_file(filename): if filename.endswith(".yaml"): # Load the custom YAML tags configure_yaml() + configure_output(use_unicode=unicode_output) content = yaml.load(content) else: raise ValueError("Unsupported filetype: '%s'" % filename) diff --git a/charlatan/fixtures_manager.py b/charlatan/fixtures_manager.py index 888bf99..0901905 100644 --- a/charlatan/fixtures_manager.py +++ b/charlatan/fixtures_manager.py @@ -47,10 +47,11 @@ class FixturesManager(object): """ - def __init__(self, db_session=None): + def __init__(self, db_session=None, unicode_output=False): self.hooks = {} self.session = db_session self.installed_keys = [] + self.unicode_output = unicode_output def load(self, filename, models_package=""): """Pre-load the fixtures. @@ -87,7 +88,7 @@ def _load_fixtures(self, filename): :param str filename: file that holds the fixture data """ - content = load_file(filename) + content = load_file(filename, self.unicode_output) fixtures = {} for k, v in _compat.iteritems(content): @@ -421,7 +422,7 @@ def set_hook(self, hookname, func): :param function func: """ - if not hookname in ALLOWED_HOOKS: + if hookname not in ALLOWED_HOOKS: raise KeyError("'%s' is not an allowed hook." % hookname) self.hooks[hookname] = func diff --git a/charlatan/tests/data/strings.yaml b/charlatan/tests/data/strings.yaml new file mode 100644 index 0000000..eebe24e --- /dev/null +++ b/charlatan/tests/data/strings.yaml @@ -0,0 +1,2 @@ +foo: bar +baz: foobar diff --git a/charlatan/tests/test_strings.py b/charlatan/tests/test_strings.py new file mode 100644 index 0000000..cf8e6b1 --- /dev/null +++ b/charlatan/tests/test_strings.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import +from sys import version_info + +import unittest +from yaml import add_constructor +from yaml.constructor import SafeConstructor + +from charlatan import file_format, testing + + +class TestUnicodeLoad(testing.TestCase): + + def setUp(self): + # preserve the original constructor for strings + self.str_constructor = SafeConstructor.yaml_constructors[ + u'tag:yaml.org,2002:str' + ] + self.yaml = file_format.load_file( + './charlatan/tests/data/strings.yaml', + unicode_output=True, + ) + + def tearDown(self): + # reset the constructor + add_constructor(u'tag:yaml.org,2002:str', self.str_constructor) + + @unittest.skipIf(version_info[0] == 3, 'Unicode is undefined in Python 3') + def test_strings_are_unicode(self): + """Assert all strings are loaded as unicode""" + for key, val in self.yaml.items(): + self.assertTrue(isinstance(key, unicode)) # noqa + self.assertTrue(isinstance(val, unicode)) # noqa + + +class TestStringLoad(testing.TestCase): + + def setUp(self): + self.yaml = file_format.load_file( + './charlatan/tests/data/strings.yaml', + ) + + @unittest.skipIf(version_info[0] == 3, 'Iteration has changed in Python 3') + def test_strings_are_strings(self): + """Assert all strings are loaded as strings""" + for key, val in self.yaml.items(): + self.assertTrue(isinstance(key, str)) + self.assertTrue(isinstance(val, str)) + + @unittest.skipIf(version_info[0] == 2, 'Iteration has changed in Python 3') + def test_strings_are_strings_python3(self): + """Assert all strings are loaded as strings""" + for key, val in list(self.yaml.items()): + self.assertTrue(isinstance(key, str)) + self.assertTrue(isinstance(val, str)) diff --git a/docs/file-format.rst b/docs/file-format.rst index 7877d03..b5cbe46 100644 --- a/docs/file-format.rst +++ b/docs/file-format.rst @@ -275,3 +275,12 @@ All the same time deltas work. .. versionadded:: 0.2.9 It is now possible to use times in seconds since the epoch + +Unicode Strings +--------------- + +.. versionadded:: 0.3.5 + +In python 2 strings are not, by default, loaded as unicode. To load all the +strings from the yaml files as unicode strings, pass the option +`unicode_output` as `True` when you instantiate your fixture manager.