Repository: omry/omegaconf

Issue:
add resolve flag to save function

Discussion:

Patch:
diff --git a/news/37.feature b/news/37.feature
new file mode 100644
index 0000000..d02db7e
--- /dev/null
+++ b/news/37.feature
@@ -0,0 +1,1 @@
+OmegaConf.save() now takes a resolve flag (defaults False)
\ No newline at end of file
diff --git a/omegaconf/omegaconf.py b/omegaconf/omegaconf.py
index 7cd4568..3699447 100644
--- a/omegaconf/omegaconf.py
+++ b/omegaconf/omegaconf.py
@@ -65,13 +65,14 @@ class OmegaConf:
             raise TypeError("Unexpected file type")
 
     @staticmethod
-    def save(config, f):
+    def save(config, f, resolve=False):
         """
         Save as configuration object to a file
         :param config: omegaconf.Config object (DictConfig or ListConfig).
         :param f: filename or file object
+        :param resolve: True to save a resolved config (defaults to False)
         """
-        data = config.pretty()
+        data = config.pretty(resolve=resolve)
         if isinstance(f, str):
             with io.open(os.path.abspath(f), "w", encoding="utf-8") as f:
                 f.write(six.u(data))


Test patch:
diff --git a/tests/test_serialization.py b/tests/test_serialization.py
index 97f011b..f52e687 100644
--- a/tests/test_serialization.py
+++ b/tests/test_serialization.py
@@ -2,128 +2,77 @@
 import io
 import os
 import tempfile
-from pytest import raises
+import pytest
 from omegaconf import OmegaConf
 
 
-def save_load_file_deprecated(conf):
-    try:
-        with tempfile.NamedTemporaryFile(mode="wt", delete=False) as fp:
-            conf.save(fp.file)
-        with io.open(os.path.abspath(fp.name), "rt") as handle:
-            c2 = OmegaConf.load(handle)
-        assert conf == c2
-    finally:
-        os.unlink(fp.name)
-
-
-def save_load_filename(conf):
-    # note that delete=False here is a work around windows incompetence.
-    try:
-        with tempfile.NamedTemporaryFile(delete=False) as fp:
-            conf.save(fp.name)
-            c2 = OmegaConf.load(fp.name)
-            assert conf == c2
-    finally:
-        os.unlink(fp.name)
-
-
-# Test deprecated config.save()
-
-
-def save_load__from_file_deprecated(conf):
-    try:
-        with tempfile.NamedTemporaryFile(mode="wt", delete=False) as fp:
-            conf.save(fp.file)
-        with io.open(os.path.abspath(fp.name), "rt") as handle:
-            c2 = OmegaConf.load(handle)
-        assert conf == c2
-    finally:
-        os.unlink(fp.name)
-
-
-def save_load__from_filename_deprecated(conf):
+def save_load_filename(conf, resolve, expected):
+    if expected is None:
+        expected = conf
     # note that delete=False here is a work around windows incompetence.
     try:
         with tempfile.NamedTemporaryFile(delete=False) as fp:
-            conf.save(fp.name)
+            OmegaConf.save(conf, fp.name, resolve=resolve)
             c2 = OmegaConf.load(fp.name)
-            assert conf == c2
+            assert c2 == expected
     finally:
         os.unlink(fp.name)
 
 
-def test_save_load_file_deprecated():
-    save_load_file_deprecated(OmegaConf.create(dict(a=10)))
-
-
-def test_save_load_filename_deprecated():
-    save_load_filename(OmegaConf.create(dict(a=10)))
-
-
-def test_save_load__from_file_deprecated():
-    save_load__from_file_deprecated(OmegaConf.create(dict(a=10)))
-
-
-def test_save_load__from_filename_deprecated():
-    save_load__from_filename_deprecated(OmegaConf.create(dict(a=10)))
-
-
-def test_save_illegal_type_deprecated():
-    with raises(TypeError):
-        OmegaConf.create().save(1000)
-
-
-##############################################
-# Test OmegaConf.save()
-
-
-def save_load__from_file(conf):
+def save_load_from_file(conf, resolve, expected):
+    if expected is None:
+        expected = conf
     try:
         with tempfile.NamedTemporaryFile(mode="wt", delete=False) as fp:
-            OmegaConf.save(conf, fp.file)
+            OmegaConf.save(conf, fp.file, resolve=resolve)
         with io.open(os.path.abspath(fp.name), "rt") as handle:
             c2 = OmegaConf.load(handle)
-        assert conf == c2
+        assert c2 == expected
     finally:
         os.unlink(fp.name)
 
 
-def save_load__from_filename(conf):
+def save_load_from_filename(conf, resolve, expected):
+    if expected is None:
+        expected = conf
     # note that delete=False here is a work around windows incompetence.
     try:
         with tempfile.NamedTemporaryFile(delete=False) as fp:
-            OmegaConf.save(conf, fp.name)
+            OmegaConf.save(conf, fp.name, resolve=resolve)
             c2 = OmegaConf.load(fp.name)
-            assert conf == c2
+            assert c2 == expected
     finally:
         os.unlink(fp.name)
 
 
-def test_save_load_file():
-    save_load_file_deprecated(OmegaConf.create(dict(a=10)))
-
-
-def test_save_load_filename():
-    save_load_filename(OmegaConf.create(dict(a=10)))
-
+@pytest.mark.parametrize(
+    "cfg,resolve,expected",
+    [
+        (dict(a=10), False, None),
+        ({"foo": 10, "bar": "${foo}"}, False, None),
+        ({"foo": 10, "bar": "${foo}"}, False, {"foo": 10, "bar": 10}),
+        ([u"שלום"], False, None),
+    ],
+)
+class TestSaveLoad:
+    def test_save_load_filename(self, cfg, resolve, expected):
+        cfg = OmegaConf.create(cfg)
+        save_load_filename(cfg, resolve, expected)
 
-def test_save_load__from_file():
-    save_load__from_file(OmegaConf.create(dict(a=10)))
+    def test_save_load__from_file(self, cfg, resolve, expected):
+        cfg = OmegaConf.create(cfg)
+        save_load_from_file(cfg, resolve, expected)
 
-
-def test_save_load__from_filename():
-    save_load__from_filename(OmegaConf.create(dict(a=10)))
+    def test_save_load__from_filename(self, cfg, resolve, expected):
+        cfg = OmegaConf.create(cfg)
+        save_load_from_filename(cfg, resolve, expected)
 
 
 def test_save_illegal_type():
-    with raises(TypeError):
+    with pytest.raises(TypeError):
         OmegaConf.save(OmegaConf.create(), 1000)
 
 
-##############################################
-
-
 def test_pickle_dict():
     with tempfile.TemporaryFile() as fp:
         import pickle
@@ -146,7 +95,3 @@ def test_pickle_list():
         fp.seek(0)
         c1 = pickle.load(fp)
         assert c == c1
-
-
-def test_save_load_unicode():
-    save_load_filename(OmegaConf.create([u"שלום"]))
diff --git a/tests/test_serialization_deprecated_save.py b/tests/test_serialization_deprecated_save.py
new file mode 100644
index 0000000..66357ae
--- /dev/null
+++ b/tests/test_serialization_deprecated_save.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+import os
+import tempfile
+
+import io
+from pytest import raises
+
+from omegaconf import OmegaConf
+
+
+def save_load_file_deprecated(conf):
+    try:
+        with tempfile.NamedTemporaryFile(mode="wt", delete=False) as fp:
+            conf.save(fp.file)
+        with io.open(os.path.abspath(fp.name), "rt") as handle:
+            c2 = OmegaConf.load(handle)
+        assert conf == c2
+    finally:
+        os.unlink(fp.name)
+
+
+def save_load_filename(conf):
+    # note that delete=False here is a work around windows incompetence.
+    try:
+        with tempfile.NamedTemporaryFile(delete=False) as fp:
+            conf.save(fp.name)
+            c2 = OmegaConf.load(fp.name)
+            assert conf == c2
+    finally:
+        os.unlink(fp.name)
+
+
+# Test deprecated config.save()
+
+
+def save_load__from_file_deprecated(conf):
+    try:
+        with tempfile.NamedTemporaryFile(mode="wt", delete=False) as fp:
+            conf.save(fp.file)
+        with io.open(os.path.abspath(fp.name), "rt") as handle:
+            c2 = OmegaConf.load(handle)
+        assert conf == c2
+    finally:
+        os.unlink(fp.name)
+
+
+def save_load__from_filename_deprecated(conf):
+    # note that delete=False here is a work around windows incompetence.
+    try:
+        with tempfile.NamedTemporaryFile(delete=False) as fp:
+            conf.save(fp.name)
+            c2 = OmegaConf.load(fp.name)
+            assert conf == c2
+    finally:
+        os.unlink(fp.name)
+
+
+def test_save_load_file_deprecated():
+    save_load_file_deprecated(OmegaConf.create(dict(a=10)))
+
+
+def test_save_load_filename_deprecated():
+    save_load_filename(OmegaConf.create(dict(a=10)))
+
+
+def test_save_load__from_file_deprecated():
+    save_load__from_file_deprecated(OmegaConf.create(dict(a=10)))
+
+
+def test_save_load__from_filename_deprecated():
+    save_load__from_filename_deprecated(OmegaConf.create(dict(a=10)))
+
+
+def test_save_illegal_type_deprecated():
+    with raises(TypeError):
+        OmegaConf.create().save(1000)
+
+
+def test_save_load_file():
+    save_load_file_deprecated(OmegaConf.create(dict(a=10)))
+
+
+def test_save_load_filename():
+    save_load_filename(OmegaConf.create(dict(a=10)))