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()

```

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]

{"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"}]}