prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  AttributeError: 'str' object has no attribute 'update'
  ```
  Traceback (most recent call last):
    File "/home/soul/anaconda2/lib/python2.7/runpy.py", line 174, in _run_module_as_main
      "__main__", fname, loader, pkg_name)
    File "/home/soul/anaconda2/lib/python2.7/runpy.py", line 72, in _run_code
      exec code in run_globals
    File "/home/soul/projects/opennmt-tf/OpenNMT-tf/bin/main.py", line 275, in <module>
      main()
    File "/home/soul/projects/opennmt-tf/OpenNMT-tf/bin/main.py", line 225, in main
      config = load_config(args.config)
    File "opennmt/config.py", line 48, in load_config
      config[section].update(subconfig[section])
  AttributeError: 'str' object has no attribute 'update'
  ```
  The attribute that caused it was "model_dir", where its value was a string.
  
  The config file that I used:
  ```
  # The directory where models and summaries will be saved. It is created if it does not exist.
  model_dir: enfr
  
  data:
    train_features_file: data/enfr/src-train.txt
    train_labels_file: data/enfr/tgt-train.txt
    eval_features_file: data/enfr/src-val.txt
    eval_labels_file: data/enfr/tgt-val.txt
  
    # (optional) Models may require additional resource files (e.g. vocabularies).
    source_words_vocabulary: data/enfr/src-vocab.txt
    target_words_vocabulary: data/enfr/tgt-vocab.txt
  
  # Model and optimization parameters.
  params:
    # The optimizer class name in tf.train or tf.contrib.opt.
    optimizer: AdamOptimizer
    learning_rate: 0.1
  
    # (optional) Maximum gradients norm (default: None).
    clip_gradients: 5.0
    # (optional) The type of learning rate decay (default: None). See:
    #  * https://www.tensorflow.org/versions/master/api_guides/python/train#Decaying_the_learning_rate
    #  * opennmt/utils/decay.py
    # This value may change the semantics of other decay options. See the documentation or the code.
    decay_type: exponential_decay
    # (optional unless decay_type is set) The learning rate decay rate.
    decay_rate: 0.9
    # (optional unless decay_type is set) Decay every this many steps.
    decay_steps: 10000
    # (optional) If true, the learning rate is decayed in a staircase fashion (default: True).
    staircase: true
    # (optional) After how many steps to start the decay (default: 0).
    start_decay_steps: 50000
    # (optional) Stop decay when this learning rate value is reached (default: 0).
    minimum_learning_rate: 0.0001
    # (optional) Width of the beam search (default: 1).
    beam_width: 5
    # (optional) Length penaly weight to apply on hypotheses (default: 0).
    length_penalty: 0.2
    # (optional) Maximum decoding iterations before stopping (default: 250).
    maximum_iterations: 200
  
  # Training options.
  train:
    batch_size: 64
  
    # (optional) Save a checkpoint every this many steps.
    save_checkpoints_steps: 5000
    # (optional) How many checkpoints to keep on disk.
    keep_checkpoint_max: 3
    # (optional) Save summaries every this many steps.
    save_summary_steps: 100
    # (optional) Train for this many steps. If not set, train forever.
    train_steps: 1000000
    # (optional) Evaluate every this many seconds (default: 3600).
    eval_delay: 7200
    # (optional) Save evaluation predictions in model_dir/eval/.
    save_eval_predictions: false
    # (optional) The maximum length of feature sequences during training (default: None).
    maximum_features_length: 70
    # (optional) The maximum length of label sequences during training (default: None).
    maximum_labels_length: 70
    # (optional) The number of buckets by sequence length to improve training efficiency (default: 5).
    num_buckets: 5
    # (optional) The number of threads to use for processing data in parallel (default: number of logical cores).
    num_parallel_process_calls: 4
    # (optional) The data pre-fetch buffer size, e.g. for shuffling examples (default: batch_size * 1000).
    buffer_size: 10000
  
  # (optional) Inference options.
  infer:
    # (optional) The batch size to use (default: 1).
    batch_size: 10
    # (optional) The number of threads to use for processing data in parallel (default: number of logical cores).
    num_parallel_process_calls: 8
    # (optional) The data pre-fetch buffer size when processing data in parallel (default: batch_size * 10).
    buffer_size: 100
    # (optional) For compatible models, the number of hypotheses to output (default: 1).
    n_best: 1
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `opennmt/config.py`
  Content:
  ```
  1 """Defines functions related to configuration files."""
  2 
  3 from importlib import import_module
  4 
  5 import yaml
  6 
  7 
  8 def load_model_module(path):
  9   """Loads a model configuration file.
  10 
  11   Args:
  12     path: The relative path to the configuration file.
  13 
  14   Returns:
  15     A Python module.
  16   """
  17   module, _ = path.rsplit(".", 1)
  18   module = module.replace("/", ".")
  19   module = import_module(module)
  20 
  21   if not hasattr(module, "model"):
  22     raise ImportError("No model defined in {}".format(path))
  23 
  24   return module
  25 
  26 def load_config(config_paths, config=None):
  27   """Loads configuration files.
  28 
  29   Args:
  30     config_paths: A list of configuration files.
  31     config: A (possibly non empty) config dictionary to fill.
  32 
  33   Returns:
  34     The configuration dictionary.
  35   """
  36   if config is None:
  37     config = {}
  38 
  39   for config_path in config_paths:
  40     with open(config_path) as config_file:
  41       subconfig = yaml.load(config_file.read())
  42 
  43       # Add or update section in main configuration.
  44       for section in subconfig:
  45         if section in config:
  46           config[section].update(subconfig[section])
  47         else:
  48           config[section] = subconfig[section]
  49 
  50   return config
  51
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/opennmt/config.py b/opennmt/config.py
  --- a/opennmt/config.py
  +++ b/opennmt/config.py
  @@ -43,7 +43,10 @@
         # Add or update section in main configuration.
         for section in subconfig:
           if section in config:
  -          config[section].update(subconfig[section])
  +          if isinstance(config[section], dict):
  +            config[section].update(subconfig[section])
  +          else:
  +            config[section] = subconfig[section]
           else:
             config[section] = subconfig[section]
  
verification_info: {"golden_diff": "diff --git a/opennmt/config.py b/opennmt/config.py\n--- a/opennmt/config.py\n+++ b/opennmt/config.py\n@@ -43,7 +43,10 @@\n       # Add or update section in main configuration.\n       for section in subconfig:\n         if section in config:\n-          config[section].update(subconfig[section])\n+          if isinstance(config[section], dict):\n+            config[section].update(subconfig[section])\n+          else:\n+            config[section] = subconfig[section]\n         else:\n           config[section] = subconfig[section]\n", "issue": "AttributeError: 'str' object has no attribute 'update'\n```\r\nTraceback (most recent call last):\r\n  File \"/home/soul/anaconda2/lib/python2.7/runpy.py\", line 174, in _run_module_as_main\r\n    \"__main__\", fname, loader, pkg_name)\r\n  File \"/home/soul/anaconda2/lib/python2.7/runpy.py\", line 72, in _run_code\r\n    exec code in run_globals\r\n  File \"/home/soul/projects/opennmt-tf/OpenNMT-tf/bin/main.py\", line 275, in <module>\r\n    main()\r\n  File \"/home/soul/projects/opennmt-tf/OpenNMT-tf/bin/main.py\", line 225, in main\r\n    config = load_config(args.config)\r\n  File \"opennmt/config.py\", line 48, in load_config\r\n    config[section].update(subconfig[section])\r\nAttributeError: 'str' object has no attribute 'update'\r\n```\r\nThe attribute that caused it was \"model_dir\", where its value was a string.\r\n\r\nThe config file that I used:\r\n```\r\n# The directory where models and summaries will be saved. It is created if it does not exist.\r\nmodel_dir: enfr\r\n\r\ndata:\r\n  train_features_file: data/enfr/src-train.txt\r\n  train_labels_file: data/enfr/tgt-train.txt\r\n  eval_features_file: data/enfr/src-val.txt\r\n  eval_labels_file: data/enfr/tgt-val.txt\r\n\r\n  # (optional) Models may require additional resource files (e.g. vocabularies).\r\n  source_words_vocabulary: data/enfr/src-vocab.txt\r\n  target_words_vocabulary: data/enfr/tgt-vocab.txt\r\n\r\n# Model and optimization parameters.\r\nparams:\r\n  # The optimizer class name in tf.train or tf.contrib.opt.\r\n  optimizer: AdamOptimizer\r\n  learning_rate: 0.1\r\n\r\n  # (optional) Maximum gradients norm (default: None).\r\n  clip_gradients: 5.0\r\n  # (optional) The type of learning rate decay (default: None). See:\r\n  #  * https://www.tensorflow.org/versions/master/api_guides/python/train#Decaying_the_learning_rate\r\n  #  * opennmt/utils/decay.py\r\n  # This value may change the semantics of other decay options. See the documentation or the code.\r\n  decay_type: exponential_decay\r\n  # (optional unless decay_type is set) The learning rate decay rate.\r\n  decay_rate: 0.9\r\n  # (optional unless decay_type is set) Decay every this many steps.\r\n  decay_steps: 10000\r\n  # (optional) If true, the learning rate is decayed in a staircase fashion (default: True).\r\n  staircase: true\r\n  # (optional) After how many steps to start the decay (default: 0).\r\n  start_decay_steps: 50000\r\n  # (optional) Stop decay when this learning rate value is reached (default: 0).\r\n  minimum_learning_rate: 0.0001\r\n  # (optional) Width of the beam search (default: 1).\r\n  beam_width: 5\r\n  # (optional) Length penaly weight to apply on hypotheses (default: 0).\r\n  length_penalty: 0.2\r\n  # (optional) Maximum decoding iterations before stopping (default: 250).\r\n  maximum_iterations: 200\r\n\r\n# Training options.\r\ntrain:\r\n  batch_size: 64\r\n\r\n  # (optional) Save a checkpoint every this many steps.\r\n  save_checkpoints_steps: 5000\r\n  # (optional) How many checkpoints to keep on disk.\r\n  keep_checkpoint_max: 3\r\n  # (optional) Save summaries every this many steps.\r\n  save_summary_steps: 100\r\n  # (optional) Train for this many steps. If not set, train forever.\r\n  train_steps: 1000000\r\n  # (optional) Evaluate every this many seconds (default: 3600).\r\n  eval_delay: 7200\r\n  # (optional) Save evaluation predictions in model_dir/eval/.\r\n  save_eval_predictions: false\r\n  # (optional) The maximum length of feature sequences during training (default: None).\r\n  maximum_features_length: 70\r\n  # (optional) The maximum length of label sequences during training (default: None).\r\n  maximum_labels_length: 70\r\n  # (optional) The number of buckets by sequence length to improve training efficiency (default: 5).\r\n  num_buckets: 5\r\n  # (optional) The number of threads to use for processing data in parallel (default: number of logical cores).\r\n  num_parallel_process_calls: 4\r\n  # (optional) The data pre-fetch buffer size, e.g. for shuffling examples (default: batch_size * 1000).\r\n  buffer_size: 10000\r\n\r\n# (optional) Inference options.\r\ninfer:\r\n  # (optional) The batch size to use (default: 1).\r\n  batch_size: 10\r\n  # (optional) The number of threads to use for processing data in parallel (default: number of logical cores).\r\n  num_parallel_process_calls: 8\r\n  # (optional) The data pre-fetch buffer size when processing data in parallel (default: batch_size * 10).\r\n  buffer_size: 100\r\n  # (optional) For compatible models, the number of hypotheses to output (default: 1).\r\n  n_best: 1\r\n```\n", "before_files": [{"content": "\"\"\"Defines functions related to configuration files.\"\"\"\n\nfrom importlib import import_module\n\nimport yaml\n\n\ndef load_model_module(path):\n  \"\"\"Loads a model configuration file.\n\n  Args:\n    path: The relative path to the configuration file.\n\n  Returns:\n    A Python module.\n  \"\"\"\n  module, _ = path.rsplit(\".\", 1)\n  module = module.replace(\"/\", \".\")\n  module = import_module(module)\n\n  if not hasattr(module, \"model\"):\n    raise ImportError(\"No model defined in {}\".format(path))\n\n  return module\n\ndef load_config(config_paths, config=None):\n  \"\"\"Loads configuration files.\n\n  Args:\n    config_paths: A list of configuration files.\n    config: A (possibly non empty) config dictionary to fill.\n\n  Returns:\n    The configuration dictionary.\n  \"\"\"\n  if config is None:\n    config = {}\n\n  for config_path in config_paths:\n    with open(config_path) as config_file:\n      subconfig = yaml.load(config_file.read())\n\n      # Add or update section in main configuration.\n      for section in subconfig:\n        if section in config:\n          config[section].update(subconfig[section])\n        else:\n          config[section] = subconfig[section]\n\n  return config\n", "path": "opennmt/config.py"}], "after_files": [{"content": "\"\"\"Defines functions related to configuration files.\"\"\"\n\nfrom importlib import import_module\n\nimport yaml\n\n\ndef load_model_module(path):\n  \"\"\"Loads a model configuration file.\n\n  Args:\n    path: The relative path to the configuration file.\n\n  Returns:\n    A Python module.\n  \"\"\"\n  module, _ = path.rsplit(\".\", 1)\n  module = module.replace(\"/\", \".\")\n  module = import_module(module)\n\n  if not hasattr(module, \"model\"):\n    raise ImportError(\"No model defined in {}\".format(path))\n\n  return module\n\ndef load_config(config_paths, config=None):\n  \"\"\"Loads configuration files.\n\n  Args:\n    config_paths: A list of configuration files.\n    config: A (possibly non empty) config dictionary to fill.\n\n  Returns:\n    The configuration dictionary.\n  \"\"\"\n  if config is None:\n    config = {}\n\n  for config_path in config_paths:\n    with open(config_path) as config_file:\n      subconfig = yaml.load(config_file.read())\n\n      # Add or update section in main configuration.\n      for section in subconfig:\n        if section in config:\n          if isinstance(config[section], dict):\n            config[section].update(subconfig[section])\n          else:\n            config[section] = subconfig[section]\n        else:\n          config[section] = subconfig[section]\n\n  return config\n", "path": "opennmt/config.py"}]}