diff options
-rw-r--r-- | _test/roundtrip.py | 2 | ||||
-rw-r--r-- | _test/test_yamlobject.py | 40 | ||||
-rw-r--r-- | constructor.py | 36 | ||||
-rw-r--r-- | representer.py | 6 |
4 files changed, 72 insertions, 12 deletions
diff --git a/_test/roundtrip.py b/_test/roundtrip.py index 86e4862..c9b4ffb 100644 --- a/_test/roundtrip.py +++ b/_test/roundtrip.py @@ -228,7 +228,7 @@ def save_and_run(program, base_dir=None, file_name=None): print('running:', *cmd) check_output(cmd, stderr=STDOUT, universal_newlines=True) except CalledProcessError as exception: - print("##### Running '{} {}' FAILED #####".format(sys.exeutable, file_name)) + print("##### Running '{} {}' FAILED #####".format(sys.executable, file_name)) print(exception.output) return exception.returncode return 0 diff --git a/_test/test_yamlobject.py b/_test/test_yamlobject.py index 1d730b5..2cb7b11 100644 --- a/_test/test_yamlobject.py +++ b/_test/test_yamlobject.py @@ -2,6 +2,7 @@ from __future__ import print_function +import sys import pytest # NOQA from roundtrip import save_and_run # NOQA @@ -42,3 +43,42 @@ def test_monster(tmpdir): """) ''' assert save_and_run(program_src, tmpdir) == 0 + + + +@pytest.mark.skipif(sys.version_info < (3, 0), reason='no __qualname__') +def test_qualified_name00(tmpdir): + """issue 214""" + program_src = u'''\ + from ruamel.yaml import YAML + from ruamel.yaml.compat import StringIO + + class A: + def f(self): + pass + + yaml = YAML(typ='unsafe') + buf = StringIO() + yaml.dump(A.f, buf) + res = buf.getvalue() + assert res == '!!python/name:__main__.A.f \\n...\\n' + x = yaml.load(res) + assert x == A.f + ''' + assert save_and_run(program_src, tmpdir) == 0 + + +@pytest.mark.skipif(sys.version_info < (3, 0), reason='no __qualname__') +def test_qualified_name01(tmpdir): + """issue 214""" + from ruamel.yaml import YAML + import ruamel.yaml.comments + from ruamel.yaml.compat import StringIO + + yaml = YAML(typ='unsafe') + buf = StringIO() + yaml.dump(ruamel.yaml.comments.CommentedBase.yaml_anchor, buf) + res = buf.getvalue() + assert res == '!!python/name:ruamel.yaml.comments.CommentedBase.yaml_anchor \n...\n' + x = yaml.load(res) + assert x == ruamel.yaml.comments.CommentedBase.yaml_anchor diff --git a/constructor.py b/constructor.py index 6de5181..ab3ebf5 100644 --- a/constructor.py +++ b/constructor.py @@ -773,10 +773,20 @@ class Constructor(SafeConstructor): mark, ) if u'.' in name: - module_name, object_name = name.rsplit('.', 1) + lname = name.split('.') + lmodule_name, lobject_name = lname, [] + while len(lmodule_name) > 1: + lobject_name.insert(0, lmodule_name.pop()) + module_name = '.'.join(lmodule_name) + try: + __import__(module_name) + # object_name = '.'.join(object_name) + break + except ImportError as exc: + continue else: module_name = builtins_module - object_name = name + object_name = [name] try: __import__(module_name) except ImportError as exc: @@ -787,14 +797,20 @@ class Constructor(SafeConstructor): mark, ) module = sys.modules[module_name] - if not hasattr(module, object_name): - raise ConstructorError( - 'while constructing a Python object', - mark, - 'cannot find %r in the module %r' % (utf8(object_name), module.__name__), - mark, - ) - return getattr(module, object_name) + object_name = '.'.join(lobject_name) + obj = module + while lobject_name: + if not hasattr(obj, lobject_name[0]): + + raise ConstructorError( + 'while constructing a Python object', + mark, + 'cannot find %r in the module %r' % ( + utf8(object_name), module.__name__), + mark, + ) + obj = getattr(obj, lobject_name.pop(0)) + return obj def construct_python_name(self, suffix, node): # type: (Any, Any) -> Any diff --git a/representer.py b/representer.py index a659977..c663397 100644 --- a/representer.py +++ b/representer.py @@ -483,7 +483,11 @@ class Representer(SafeRepresenter): def represent_name(self, data): # type: (Any) -> Any - name = u'%s.%s' % (data.__module__, data.__name__) + try: + name = u'%s.%s' % (data.__module__, data.__qualname__) + except AttributeError: + # probably PY2 + name = u'%s.%s' % (data.__module__, data.__name__) return self.represent_scalar(u'tag:yaml.org,2002:python/name:' + name, "") def represent_module(self, data): |