Skip to content

Commit

Permalink
Fixed a regression from 1.6.1 where using ruamel.yaml safe_load would…
Browse files Browse the repository at this point in the history
… cause normal python objects like python/str objects to not be read properly from the yaml files. This fixes it by adding back all the normal python objects that is normally loaded during yaml loading.
  • Loading branch information
Grokzen committed Oct 19, 2019
1 parent 75cf1e9 commit 68405ed
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 3 deletions.
2 changes: 2 additions & 0 deletions docs/release-notes.rst
Expand Up @@ -12,6 +12,8 @@ Next release
- Implement new type `url` that uses a relative simple regex to validate url:s according to RFC 1808
- Update minimum version of ruamel.yaml to 0.16.0
- Update minimum version of python-dateutil to 2.8.0
- Fixed a regression from 1.6.1 where ruamel.yaml safe_load would break for all built-in custom python tags.
All normal python tags should now be possible to use again.


1.7.0 (October 3, 2018)
Expand Down
3 changes: 3 additions & 0 deletions pykwalify/compat.py
Expand Up @@ -6,6 +6,9 @@
# 3rd party imports
from ruamel import yaml # NOQA: F401

# Build our global yml object that will be used in all other operations in the code
yml = yaml.YAML(typ='safe', pure=True)


if sys.version_info[0] < 3:
# Python 2.x.x series
Expand Down
21 changes: 18 additions & 3 deletions pykwalify/core.py
Expand Up @@ -22,8 +22,9 @@
from pykwalify.types import is_scalar, is_string, tt

# 3rd party imports
from pykwalify.compat import yaml
from dateutil.parser import parse
from pykwalify.compat import yml
from ruamel.yaml.constructor import Constructor

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -62,6 +63,20 @@ def __init__(self, source_file=None, schema_files=None, source_data=None, schema
self.fix_ruby_style_regex = fix_ruby_style_regex
self.allow_assertions = allow_assertions

# Patch in all the normal python types into the yaml load instance so we can use all the
# internal python types in the yaml loading.
yml.constructor.add_constructor('tag:yaml.org,2002:python/bool', Constructor.construct_yaml_bool)
yml.constructor.add_constructor('tag:yaml.org,2002:python/complex', Constructor.construct_python_complex)
yml.constructor.add_constructor('tag:yaml.org,2002:python/dict', Constructor.construct_yaml_map)
yml.constructor.add_constructor('tag:yaml.org,2002:python/float', Constructor.construct_yaml_float)
yml.constructor.add_constructor('tag:yaml.org,2002:python/int', Constructor.construct_yaml_int)
yml.constructor.add_constructor('tag:yaml.org,2002:python/list', Constructor.construct_yaml_seq)
yml.constructor.add_constructor('tag:yaml.org,2002:python/long', Constructor.construct_python_long)
yml.constructor.add_constructor('tag:yaml.org,2002:python/none', Constructor.construct_yaml_null)
yml.constructor.add_constructor('tag:yaml.org,2002:python/str', Constructor.construct_python_str)
yml.constructor.add_constructor('tag:yaml.org,2002:python/tuple', Constructor.construct_python_tuple)
yml.constructor.add_constructor('tag:yaml.org,2002:python/unicode', Constructor.construct_python_unicode)

if source_file is not None:
if not os.path.exists(source_file):
raise CoreError(u"Provided source_file do not exists on disk: {0}".format(source_file))
Expand All @@ -70,7 +85,7 @@ def __init__(self, source_file=None, schema_files=None, source_data=None, schema
if source_file.endswith(".json"):
self.source = json.load(stream)
elif source_file.endswith(".yaml") or source_file.endswith('.yml'):
self.source = yaml.safe_load(stream)
self.source = yml.load(stream)
else:
raise CoreError(u"Unable to load source_file. Unknown file format of specified file path: {0}".format(source_file))

Expand All @@ -88,7 +103,7 @@ def __init__(self, source_file=None, schema_files=None, source_data=None, schema
if f.endswith(".json"):
data = json.load(stream)
elif f.endswith(".yaml") or f.endswith(".yml"):
data = yaml.safe_load(stream)
data = yml.load(stream)
if not data:
raise CoreError(u"No data loaded from file : {0}".format(f))
else:
Expand Down
25 changes: 25 additions & 0 deletions tests/test_core.py
Expand Up @@ -354,6 +354,31 @@ def test_multi_file_support(self):
),
)

def test_python_obj_loading(self, tmp_path):
schema = """
allowempty: True
mapping:
intents:
type: !!python/str "seq"
sequence:
- type: !!python/str "str"
"""
data = """
intents:
- greet
- default
- goodbye
"""
schema_path = os.path.join(tmp_path, 'schema.yaml')
with open(schema_path, 'w') as stream:
stream.write(schema)
data_path = os.path.join(tmp_path, 'data.yaml')
with open(data_path, 'w') as stream:
stream.write(data)

c = Core(source_file=data_path, schema_files=[schema_path])
c.validate()

def test_core_files(self):
# These tests should pass with no exception raised
pass_tests = [
Expand Down

0 comments on commit 68405ed

Please sign in to comment.