PyYAML - Saving data to .yaml files











up vote
0
down vote

favorite
1












So I've picked up PyYAML over the past few days but I feel like some of the documentation is vague or I'm misinterpreting it. Here is a function for writing data to a .yaml which can write the values to each element I have in the list:



def writeSave(filename, **kwargs):
with open(filename, 'r') as yamlFile:
yamlDict = yaml.load(yamlFile)
if not yamlDict: yamlDict = {}

with open(filename, 'w') as write:
z = yamlDict.copy()
z.update(kwargs)
yaml.dump(z, write)


Which will then overwrite the values below when called:



saveData:
{mission_state: 7, playername: 'steve'}


Using this function seems simple:



writeSave('../path/savedata.yaml', mission_state=2)


Which will then change the mission_state in the list.



I don't know if I've done this smoothly or if there is a better practice to performing these kind of functions. If there are, it'd be nice to have some kind of pointers.



Is there a way to make this more readable? Maybe more readable vars or more commenting?










share|improve this question




























    up vote
    0
    down vote

    favorite
    1












    So I've picked up PyYAML over the past few days but I feel like some of the documentation is vague or I'm misinterpreting it. Here is a function for writing data to a .yaml which can write the values to each element I have in the list:



    def writeSave(filename, **kwargs):
    with open(filename, 'r') as yamlFile:
    yamlDict = yaml.load(yamlFile)
    if not yamlDict: yamlDict = {}

    with open(filename, 'w') as write:
    z = yamlDict.copy()
    z.update(kwargs)
    yaml.dump(z, write)


    Which will then overwrite the values below when called:



    saveData:
    {mission_state: 7, playername: 'steve'}


    Using this function seems simple:



    writeSave('../path/savedata.yaml', mission_state=2)


    Which will then change the mission_state in the list.



    I don't know if I've done this smoothly or if there is a better practice to performing these kind of functions. If there are, it'd be nice to have some kind of pointers.



    Is there a way to make this more readable? Maybe more readable vars or more commenting?










    share|improve this question


























      up vote
      0
      down vote

      favorite
      1









      up vote
      0
      down vote

      favorite
      1






      1





      So I've picked up PyYAML over the past few days but I feel like some of the documentation is vague or I'm misinterpreting it. Here is a function for writing data to a .yaml which can write the values to each element I have in the list:



      def writeSave(filename, **kwargs):
      with open(filename, 'r') as yamlFile:
      yamlDict = yaml.load(yamlFile)
      if not yamlDict: yamlDict = {}

      with open(filename, 'w') as write:
      z = yamlDict.copy()
      z.update(kwargs)
      yaml.dump(z, write)


      Which will then overwrite the values below when called:



      saveData:
      {mission_state: 7, playername: 'steve'}


      Using this function seems simple:



      writeSave('../path/savedata.yaml', mission_state=2)


      Which will then change the mission_state in the list.



      I don't know if I've done this smoothly or if there is a better practice to performing these kind of functions. If there are, it'd be nice to have some kind of pointers.



      Is there a way to make this more readable? Maybe more readable vars or more commenting?










      share|improve this question















      So I've picked up PyYAML over the past few days but I feel like some of the documentation is vague or I'm misinterpreting it. Here is a function for writing data to a .yaml which can write the values to each element I have in the list:



      def writeSave(filename, **kwargs):
      with open(filename, 'r') as yamlFile:
      yamlDict = yaml.load(yamlFile)
      if not yamlDict: yamlDict = {}

      with open(filename, 'w') as write:
      z = yamlDict.copy()
      z.update(kwargs)
      yaml.dump(z, write)


      Which will then overwrite the values below when called:



      saveData:
      {mission_state: 7, playername: 'steve'}


      Using this function seems simple:



      writeSave('../path/savedata.yaml', mission_state=2)


      Which will then change the mission_state in the list.



      I don't know if I've done this smoothly or if there is a better practice to performing these kind of functions. If there are, it'd be nice to have some kind of pointers.



      Is there a way to make this more readable? Maybe more readable vars or more commenting?







      python yaml






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Feb 3 at 3:46

























      asked Feb 3 at 3:35









      iZodiac

      10815




      10815






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          4
          down vote



          accepted











          • First, Python has an official style-guide, PEP8, which you should follow. It recommends using lower_case for functions and variables.


          • I would also rename your function, since write_save does not say what this function is doing. I think overwrite_setting or update_value or something similar would be better.


          • You might want to add a check if any keyword arguments are passed to the function. Either raise an exception (a simple AssertionError might be enough), or at least don't waste time reading the file and writing the same content back.


          • While open opens a file in read-mode by default, here I think it is actually fine to open it once explicitly with 'r' and then with 'w'.


          • Your z = yamDict.copy() should be completely unnecessary. Mutating the original dictionary does not do any harm. The updating does not need to be within the with block either.


          • Finally, you could use or for the check of an empty dictionary.



          With all of the above changes, your code would become:



          import yaml

          def update_value(filename, **kwargs):
          assert kwargs
          with open(filename, 'r') as f:
          yaml_dict = yaml.load(f) or {}
          yaml_dict.update(kwargs)
          with open(filename, 'w') as f:
          yaml.dump(yaml_dict, f)




          If you have only one thread, you could skip the reading of the config everytime you want to change a value and instead keep the dictionary in memory (after having it read once at the beginning). You will still want the write to save state, though. For this you might want to have a Config class, derived from dict:



          import os

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          def __setitem__(self, key, value):
          super(Config, self).__setitem__(key, value)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def __delitem__(self, key):
          super(Config, self).__delitem__(key)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def update(self, kwargs):
          super(Config, self).update(kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)


          You might want to define a decorator to add the dumping part to the methods:



          import functools

          def dumps(func):
          @functools.wraps(func)
          def wrapper(self, *args, **kwargs):
          ret = func(self, *args, **kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)
          return ret
          return wrapper

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          __setitem__ = dumps(dict.__setitem__)
          __delitem__ = dumps(dict.__delitem__)
          update = dumps(dict.update)


          You can use this class like a dict, but every change to the dictionary is also dumped to the yaml file. The file is only read once (when the config is initialized), so changes to the file will only be visible when the script is re-started.



          cfg = Config("test.yaml")
          print(cfg)
          cfg['a'] = 3
          print(cfg)
          cfg.update({"b": 4})
          cfg.update(c=5)
          del cfg['a']
          print(cfg)





          share|improve this answer



















          • 1




            Amazing! Really insightful and well explained. I specifically enjoyed the derived dict class since that can really simplify things for me.
            – iZodiac
            Feb 3 at 14:20











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186653%2fpyyaml-saving-data-to-yaml-files%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          4
          down vote



          accepted











          • First, Python has an official style-guide, PEP8, which you should follow. It recommends using lower_case for functions and variables.


          • I would also rename your function, since write_save does not say what this function is doing. I think overwrite_setting or update_value or something similar would be better.


          • You might want to add a check if any keyword arguments are passed to the function. Either raise an exception (a simple AssertionError might be enough), or at least don't waste time reading the file and writing the same content back.


          • While open opens a file in read-mode by default, here I think it is actually fine to open it once explicitly with 'r' and then with 'w'.


          • Your z = yamDict.copy() should be completely unnecessary. Mutating the original dictionary does not do any harm. The updating does not need to be within the with block either.


          • Finally, you could use or for the check of an empty dictionary.



          With all of the above changes, your code would become:



          import yaml

          def update_value(filename, **kwargs):
          assert kwargs
          with open(filename, 'r') as f:
          yaml_dict = yaml.load(f) or {}
          yaml_dict.update(kwargs)
          with open(filename, 'w') as f:
          yaml.dump(yaml_dict, f)




          If you have only one thread, you could skip the reading of the config everytime you want to change a value and instead keep the dictionary in memory (after having it read once at the beginning). You will still want the write to save state, though. For this you might want to have a Config class, derived from dict:



          import os

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          def __setitem__(self, key, value):
          super(Config, self).__setitem__(key, value)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def __delitem__(self, key):
          super(Config, self).__delitem__(key)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def update(self, kwargs):
          super(Config, self).update(kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)


          You might want to define a decorator to add the dumping part to the methods:



          import functools

          def dumps(func):
          @functools.wraps(func)
          def wrapper(self, *args, **kwargs):
          ret = func(self, *args, **kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)
          return ret
          return wrapper

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          __setitem__ = dumps(dict.__setitem__)
          __delitem__ = dumps(dict.__delitem__)
          update = dumps(dict.update)


          You can use this class like a dict, but every change to the dictionary is also dumped to the yaml file. The file is only read once (when the config is initialized), so changes to the file will only be visible when the script is re-started.



          cfg = Config("test.yaml")
          print(cfg)
          cfg['a'] = 3
          print(cfg)
          cfg.update({"b": 4})
          cfg.update(c=5)
          del cfg['a']
          print(cfg)





          share|improve this answer



















          • 1




            Amazing! Really insightful and well explained. I specifically enjoyed the derived dict class since that can really simplify things for me.
            – iZodiac
            Feb 3 at 14:20















          up vote
          4
          down vote



          accepted











          • First, Python has an official style-guide, PEP8, which you should follow. It recommends using lower_case for functions and variables.


          • I would also rename your function, since write_save does not say what this function is doing. I think overwrite_setting or update_value or something similar would be better.


          • You might want to add a check if any keyword arguments are passed to the function. Either raise an exception (a simple AssertionError might be enough), or at least don't waste time reading the file and writing the same content back.


          • While open opens a file in read-mode by default, here I think it is actually fine to open it once explicitly with 'r' and then with 'w'.


          • Your z = yamDict.copy() should be completely unnecessary. Mutating the original dictionary does not do any harm. The updating does not need to be within the with block either.


          • Finally, you could use or for the check of an empty dictionary.



          With all of the above changes, your code would become:



          import yaml

          def update_value(filename, **kwargs):
          assert kwargs
          with open(filename, 'r') as f:
          yaml_dict = yaml.load(f) or {}
          yaml_dict.update(kwargs)
          with open(filename, 'w') as f:
          yaml.dump(yaml_dict, f)




          If you have only one thread, you could skip the reading of the config everytime you want to change a value and instead keep the dictionary in memory (after having it read once at the beginning). You will still want the write to save state, though. For this you might want to have a Config class, derived from dict:



          import os

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          def __setitem__(self, key, value):
          super(Config, self).__setitem__(key, value)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def __delitem__(self, key):
          super(Config, self).__delitem__(key)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def update(self, kwargs):
          super(Config, self).update(kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)


          You might want to define a decorator to add the dumping part to the methods:



          import functools

          def dumps(func):
          @functools.wraps(func)
          def wrapper(self, *args, **kwargs):
          ret = func(self, *args, **kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)
          return ret
          return wrapper

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          __setitem__ = dumps(dict.__setitem__)
          __delitem__ = dumps(dict.__delitem__)
          update = dumps(dict.update)


          You can use this class like a dict, but every change to the dictionary is also dumped to the yaml file. The file is only read once (when the config is initialized), so changes to the file will only be visible when the script is re-started.



          cfg = Config("test.yaml")
          print(cfg)
          cfg['a'] = 3
          print(cfg)
          cfg.update({"b": 4})
          cfg.update(c=5)
          del cfg['a']
          print(cfg)





          share|improve this answer



















          • 1




            Amazing! Really insightful and well explained. I specifically enjoyed the derived dict class since that can really simplify things for me.
            – iZodiac
            Feb 3 at 14:20













          up vote
          4
          down vote



          accepted







          up vote
          4
          down vote



          accepted







          • First, Python has an official style-guide, PEP8, which you should follow. It recommends using lower_case for functions and variables.


          • I would also rename your function, since write_save does not say what this function is doing. I think overwrite_setting or update_value or something similar would be better.


          • You might want to add a check if any keyword arguments are passed to the function. Either raise an exception (a simple AssertionError might be enough), or at least don't waste time reading the file and writing the same content back.


          • While open opens a file in read-mode by default, here I think it is actually fine to open it once explicitly with 'r' and then with 'w'.


          • Your z = yamDict.copy() should be completely unnecessary. Mutating the original dictionary does not do any harm. The updating does not need to be within the with block either.


          • Finally, you could use or for the check of an empty dictionary.



          With all of the above changes, your code would become:



          import yaml

          def update_value(filename, **kwargs):
          assert kwargs
          with open(filename, 'r') as f:
          yaml_dict = yaml.load(f) or {}
          yaml_dict.update(kwargs)
          with open(filename, 'w') as f:
          yaml.dump(yaml_dict, f)




          If you have only one thread, you could skip the reading of the config everytime you want to change a value and instead keep the dictionary in memory (after having it read once at the beginning). You will still want the write to save state, though. For this you might want to have a Config class, derived from dict:



          import os

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          def __setitem__(self, key, value):
          super(Config, self).__setitem__(key, value)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def __delitem__(self, key):
          super(Config, self).__delitem__(key)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def update(self, kwargs):
          super(Config, self).update(kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)


          You might want to define a decorator to add the dumping part to the methods:



          import functools

          def dumps(func):
          @functools.wraps(func)
          def wrapper(self, *args, **kwargs):
          ret = func(self, *args, **kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)
          return ret
          return wrapper

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          __setitem__ = dumps(dict.__setitem__)
          __delitem__ = dumps(dict.__delitem__)
          update = dumps(dict.update)


          You can use this class like a dict, but every change to the dictionary is also dumped to the yaml file. The file is only read once (when the config is initialized), so changes to the file will only be visible when the script is re-started.



          cfg = Config("test.yaml")
          print(cfg)
          cfg['a'] = 3
          print(cfg)
          cfg.update({"b": 4})
          cfg.update(c=5)
          del cfg['a']
          print(cfg)





          share|improve this answer















          • First, Python has an official style-guide, PEP8, which you should follow. It recommends using lower_case for functions and variables.


          • I would also rename your function, since write_save does not say what this function is doing. I think overwrite_setting or update_value or something similar would be better.


          • You might want to add a check if any keyword arguments are passed to the function. Either raise an exception (a simple AssertionError might be enough), or at least don't waste time reading the file and writing the same content back.


          • While open opens a file in read-mode by default, here I think it is actually fine to open it once explicitly with 'r' and then with 'w'.


          • Your z = yamDict.copy() should be completely unnecessary. Mutating the original dictionary does not do any harm. The updating does not need to be within the with block either.


          • Finally, you could use or for the check of an empty dictionary.



          With all of the above changes, your code would become:



          import yaml

          def update_value(filename, **kwargs):
          assert kwargs
          with open(filename, 'r') as f:
          yaml_dict = yaml.load(f) or {}
          yaml_dict.update(kwargs)
          with open(filename, 'w') as f:
          yaml.dump(yaml_dict, f)




          If you have only one thread, you could skip the reading of the config everytime you want to change a value and instead keep the dictionary in memory (after having it read once at the beginning). You will still want the write to save state, though. For this you might want to have a Config class, derived from dict:



          import os

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          def __setitem__(self, key, value):
          super(Config, self).__setitem__(key, value)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def __delitem__(self, key):
          super(Config, self).__delitem__(key)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)

          def update(self, kwargs):
          super(Config, self).update(kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)


          You might want to define a decorator to add the dumping part to the methods:



          import functools

          def dumps(func):
          @functools.wraps(func)
          def wrapper(self, *args, **kwargs):
          ret = func(self, *args, **kwargs)
          with open(self.filename, "w") as f:
          yaml.dump(self, f)
          return ret
          return wrapper

          class Config(dict):
          def __init__(self, filename):
          self.filename = filename
          if os.path.isfile(filename):
          with open(filename) as f:
          # use super here to avoid unnecessary write
          super(Config, self).update(yaml.load(f) or {})

          __setitem__ = dumps(dict.__setitem__)
          __delitem__ = dumps(dict.__delitem__)
          update = dumps(dict.update)


          You can use this class like a dict, but every change to the dictionary is also dumped to the yaml file. The file is only read once (when the config is initialized), so changes to the file will only be visible when the script is re-started.



          cfg = Config("test.yaml")
          print(cfg)
          cfg['a'] = 3
          print(cfg)
          cfg.update({"b": 4})
          cfg.update(c=5)
          del cfg['a']
          print(cfg)






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 8 hours ago

























          answered Feb 3 at 12:19









          Graipher

          23k53384




          23k53384








          • 1




            Amazing! Really insightful and well explained. I specifically enjoyed the derived dict class since that can really simplify things for me.
            – iZodiac
            Feb 3 at 14:20














          • 1




            Amazing! Really insightful and well explained. I specifically enjoyed the derived dict class since that can really simplify things for me.
            – iZodiac
            Feb 3 at 14:20








          1




          1




          Amazing! Really insightful and well explained. I specifically enjoyed the derived dict class since that can really simplify things for me.
          – iZodiac
          Feb 3 at 14:20




          Amazing! Really insightful and well explained. I specifically enjoyed the derived dict class since that can really simplify things for me.
          – iZodiac
          Feb 3 at 14:20


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186653%2fpyyaml-saving-data-to-yaml-files%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          List directoties down one level, excluding some named directories and files

          list processes belonging to a network namespace

          list systemd RuntimeDirectory mounts