diff --git a/.circleci/config.yml b/.circleci/config.yml index acd727203..dcd4af0fe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ jobs: py27_linux: docker: # nox got requires python 3 but it can test 2.7 - - image: circleci/python:3.6 + - image: circleci/python:3.7 steps: - checkout - run: echo 'export NOX_PYTHON_VERSIONS=2.7' >> $BASH_ENV @@ -14,7 +14,7 @@ jobs: py35_linux: docker: - - image: circleci/python:3.5 + - image: circleci/python:3.7 steps: - checkout - run: echo 'export NOX_PYTHON_VERSIONS=3.5' >> $BASH_ENV @@ -23,7 +23,7 @@ jobs: py36_linux: docker: - - image: circleci/python:3.6 + - image: circleci/python:3.7 steps: - checkout - run: echo 'export NOX_PYTHON_VERSIONS=3.6' >> $BASH_ENV @@ -42,7 +42,7 @@ jobs: # Misc coverage: docker: - - image: circleci/python:3.6 + - image: circleci/python:3.7 steps: - checkout - run: sudo pip install nox diff --git a/news/66.removal b/news/66.removal new file mode 100644 index 000000000..039ff6da8 --- /dev/null +++ b/news/66.removal @@ -0,0 +1 @@ +Deprecated config.save(file) in favor of OmegaConf.save(config, file) diff --git a/noxfile.py b/noxfile.py index 6adfd9a9d..cd8a45004 100644 --- a/noxfile.py +++ b/noxfile.py @@ -26,7 +26,7 @@ def omegaconf(session): # code coverage runs with python 3.6 -@nox.session(python="3.6") +@nox.session(python="3.7") def coverage(session): session.install("--upgrade", "setuptools", "pip") session.install("coverage", "pytest") @@ -41,7 +41,7 @@ def coverage(session): session.run("coveralls", success_codes=[0, 1]) -@nox.session(python="3.6") +@nox.session(python="3.7") def lint(session): session.install("--upgrade", "setuptools", "pip") session.run("pip", "install", ".[lint]", silent=True) diff --git a/omegaconf/config.py b/omegaconf/config.py index 2fee5eea1..61de58c4d 100644 --- a/omegaconf/config.py +++ b/omegaconf/config.py @@ -1,12 +1,10 @@ import copy -import io -import os -import re import sys import warnings from abc import abstractmethod from collections import defaultdict +import re import six import yaml @@ -65,15 +63,15 @@ def __init__(self): self.__dict__["_resolver_cache"] = defaultdict(dict) def save(self, f): - data = self.pretty() - if isinstance(f, str): - with io.open(os.path.abspath(f), "w", encoding="utf-8") as f: - f.write(six.u(data)) - elif hasattr(f, "write"): - f.write(data) - f.flush() - else: - raise TypeError("Unexpected file type") + warnings.warn( + "Use OmegaConf.save(config, filename) (since 1.4.0)", + DeprecationWarning, + stacklevel=2, + ) + + from omegaconf import OmegaConf + + OmegaConf.save(self, f) def _set_parent(self, parent): assert parent is None or isinstance(parent, Config) diff --git a/omegaconf/omegaconf.py b/omegaconf/omegaconf.py index a8e75d531..e43f3befb 100644 --- a/omegaconf/omegaconf.py +++ b/omegaconf/omegaconf.py @@ -1,12 +1,13 @@ """OmegaConf module""" import copy -import io import os -import re import sys import warnings from contextlib import contextmanager +import io +import re +import six import yaml from .config import Config @@ -72,6 +73,23 @@ def load(file_): else: raise TypeError("Unexpected file type") + @staticmethod + def save(config, f): + """ + Save as configuration object to a file + :param config: omegaconf.Config object (DictConfig or ListConfig). + :param f: filename or file object + """ + data = config.pretty() + if isinstance(f, str): + with io.open(os.path.abspath(f), "w", encoding="utf-8") as f: + f.write(six.u(data)) + elif hasattr(f, "write"): + f.write(data) + f.flush() + else: + raise TypeError("Unexpected file type") + @staticmethod def from_filename(filename): warnings.warn( diff --git a/tests/test_serialization.py b/tests/test_serialization.py index 8fc89521a..4e73eb0e9 100644 --- a/tests/test_serialization.py +++ b/tests/test_serialization.py @@ -6,7 +6,7 @@ from omegaconf import OmegaConf -def save_load_file(conf): +def save_load_file_deprecated(conf): try: with tempfile.NamedTemporaryFile(mode="wt", delete=False) as fp: conf.save(fp.file) @@ -28,7 +28,10 @@ def save_load_filename(conf): os.unlink(fp.name) -def save_load__from_file(conf): +# 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) @@ -39,7 +42,7 @@ def save_load__from_file(conf): os.unlink(fp.name) -def save_load__from_filename(conf): +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: @@ -50,8 +53,55 @@ def save_load__from_filename(conf): 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): + try: + with tempfile.NamedTemporaryFile(mode="wt", delete=False) as fp: + OmegaConf.save(conf, fp.file) + with io.open(os.path.abspath(fp.name), "rt") as handle: + c2 = OmegaConf.from_file(handle) + assert conf == c2 + finally: + os.unlink(fp.name) + + +def save_load__from_filename(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) + c2 = OmegaConf.from_filename(fp.name) + assert conf == c2 + finally: + os.unlink(fp.name) + + def test_save_load_file(): - save_load_file(OmegaConf.create(dict(a=10))) + save_load_file_deprecated(OmegaConf.create(dict(a=10))) def test_save_load_filename(): @@ -66,6 +116,14 @@ def test_save_load__from_filename(): save_load__from_filename(OmegaConf.create(dict(a=10))) +def test_save_illegal_type(): + with raises(TypeError): + OmegaConf.save(OmegaConf.create(), 1000) + + +############################################## + + def test_pickle_dict(): with tempfile.TemporaryFile() as fp: import pickle @@ -92,8 +150,3 @@ def test_pickle_list(): def test_save_load_unicode(): save_load_filename(OmegaConf.create([u"שלום"])) - - -def test_save_illegal_type(): - with raises(TypeError): - OmegaConf.create().save(1000)