prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  gh: prefix doesn't work anymore
  * Cookiecutter version: 1.5.1
  * Template project url: `gh:*`
  * Python version: 2.7.13
  * Operating System: Linux
  
  ### Description:
  
  cookiecutter does not honor prefixes anymore.
  
  ### What I've run:
  
  Simply testing the example from the README doesn't work as expected:
  
  ``` bash
  $ cookiecutter gh:audreyr/cookiecutter-pypackage
  A valid repository for "gh:audreyr/cookiecutter-pypackage" could not be found in the following locations:
  gh:audreyr/cookiecutter-pypackage
  /home/me/.cookiecutters/gh:audreyr/cookiecutter-pypackage
  ```
  The same commands using the full repository path works as expected:
  
  ```bash
  $ cookiecutter https://github.com/audreyr/cookiecutter-pypackage
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `cookiecutter/config.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 
  3 """Global configuration handling."""
  4 
  5 from __future__ import unicode_literals
  6 import copy
  7 import logging
  8 import os
  9 import io
  10 
  11 import poyo
  12 
  13 from .exceptions import ConfigDoesNotExistException
  14 from .exceptions import InvalidConfiguration
  15 
  16 
  17 logger = logging.getLogger(__name__)
  18 
  19 USER_CONFIG_PATH = os.path.expanduser('~/.cookiecutterrc')
  20 
  21 BUILTIN_ABBREVIATIONS = {
  22     'gh': 'https://github.com/{0}.git',
  23     'gl': 'https://gitlab.com/{0}.git',
  24     'bb': 'https://bitbucket.org/{0}',
  25 }
  26 
  27 DEFAULT_CONFIG = {
  28     'cookiecutters_dir': os.path.expanduser('~/.cookiecutters/'),
  29     'replay_dir': os.path.expanduser('~/.cookiecutter_replay/'),
  30     'default_context': {},
  31     'abbreviations': BUILTIN_ABBREVIATIONS,
  32 }
  33 
  34 
  35 def _expand_path(path):
  36     """Expand both environment variables and user home in the given path."""
  37     path = os.path.expandvars(path)
  38     path = os.path.expanduser(path)
  39     return path
  40 
  41 
  42 def get_config(config_path):
  43     """Retrieve the config from the specified path, returning a config dict."""
  44     if not os.path.exists(config_path):
  45         raise ConfigDoesNotExistException
  46 
  47     logger.debug('config_path is {0}'.format(config_path))
  48     with io.open(config_path, encoding='utf-8') as file_handle:
  49         try:
  50             yaml_dict = poyo.parse_string(file_handle.read())
  51         except poyo.exceptions.PoyoException as e:
  52             raise InvalidConfiguration(
  53                 'Unable to parse YAML file {}. Error: {}'
  54                 ''.format(config_path, e)
  55             )
  56 
  57     config_dict = copy.copy(DEFAULT_CONFIG)
  58     config_dict.update(yaml_dict)
  59 
  60     raw_replay_dir = config_dict['replay_dir']
  61     config_dict['replay_dir'] = _expand_path(raw_replay_dir)
  62 
  63     raw_cookies_dir = config_dict['cookiecutters_dir']
  64     config_dict['cookiecutters_dir'] = _expand_path(raw_cookies_dir)
  65 
  66     return config_dict
  67 
  68 
  69 def get_user_config(config_file=None, default_config=False):
  70     """Return the user config as a dict.
  71 
  72     If ``default_config`` is True, ignore ``config_file`` and return default
  73     values for the config parameters.
  74 
  75     If a path to a ``config_file`` is given, that is different from the default
  76     location, load the user config from that.
  77 
  78     Otherwise look up the config file path in the ``COOKIECUTTER_CONFIG``
  79     environment variable. If set, load the config from this path. This will
  80     raise an error if the specified path is not valid.
  81 
  82     If the environment variable is not set, try the default config file path
  83     before falling back to the default config values.
  84     """
  85     # Do NOT load a config. Return defaults instead.
  86     if default_config:
  87         return copy.copy(DEFAULT_CONFIG)
  88 
  89     # Load the given config file
  90     if config_file and config_file is not USER_CONFIG_PATH:
  91         return get_config(config_file)
  92 
  93     try:
  94         # Does the user set up a config environment variable?
  95         env_config_file = os.environ['COOKIECUTTER_CONFIG']
  96     except KeyError:
  97         # Load an optional user config if it exists
  98         # otherwise return the defaults
  99         if os.path.exists(USER_CONFIG_PATH):
  100             return get_config(USER_CONFIG_PATH)
  101         else:
  102             return copy.copy(DEFAULT_CONFIG)
  103     else:
  104         # There is a config environment variable. Try to load it.
  105         # Do not check for existence, so invalid file paths raise an error.
  106         return get_config(env_config_file)
  107
  ```
  --- 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/cookiecutter/config.py b/cookiecutter/config.py
  --- a/cookiecutter/config.py
  +++ b/cookiecutter/config.py
  @@ -39,6 +39,25 @@
       return path
   
   
  +def merge_configs(default, overwrite):
  +    """Recursively update a dict with the key/value pair of another.
  +
  +    Dict values that are dictionaries themselves will be updated, whilst
  +    preserving existing keys.
  +    """
  +    new_config = copy.deepcopy(default)
  +
  +    for k, v in overwrite.items():
  +        # Make sure to preserve existing items in
  +        # nested dicts, for example `abbreviations`
  +        if isinstance(v, dict):
  +            new_config[k] = merge_configs(default[k], v)
  +        else:
  +            new_config[k] = v
  +
  +    return new_config
  +
  +
   def get_config(config_path):
       """Retrieve the config from the specified path, returning a config dict."""
       if not os.path.exists(config_path):
  @@ -54,8 +73,7 @@
                   ''.format(config_path, e)
               )
   
  -    config_dict = copy.copy(DEFAULT_CONFIG)
  -    config_dict.update(yaml_dict)
  +    config_dict = merge_configs(DEFAULT_CONFIG, yaml_dict)
   
       raw_replay_dir = config_dict['replay_dir']
       config_dict['replay_dir'] = _expand_path(raw_replay_dir)
  
verification_info: {"golden_diff": "diff --git a/cookiecutter/config.py b/cookiecutter/config.py\n--- a/cookiecutter/config.py\n+++ b/cookiecutter/config.py\n@@ -39,6 +39,25 @@\n     return path\n \n \n+def merge_configs(default, overwrite):\n+    \"\"\"Recursively update a dict with the key/value pair of another.\n+\n+    Dict values that are dictionaries themselves will be updated, whilst\n+    preserving existing keys.\n+    \"\"\"\n+    new_config = copy.deepcopy(default)\n+\n+    for k, v in overwrite.items():\n+        # Make sure to preserve existing items in\n+        # nested dicts, for example `abbreviations`\n+        if isinstance(v, dict):\n+            new_config[k] = merge_configs(default[k], v)\n+        else:\n+            new_config[k] = v\n+\n+    return new_config\n+\n+\n def get_config(config_path):\n     \"\"\"Retrieve the config from the specified path, returning a config dict.\"\"\"\n     if not os.path.exists(config_path):\n@@ -54,8 +73,7 @@\n                 ''.format(config_path, e)\n             )\n \n-    config_dict = copy.copy(DEFAULT_CONFIG)\n-    config_dict.update(yaml_dict)\n+    config_dict = merge_configs(DEFAULT_CONFIG, yaml_dict)\n \n     raw_replay_dir = config_dict['replay_dir']\n     config_dict['replay_dir'] = _expand_path(raw_replay_dir)\n", "issue": "gh: prefix doesn't work anymore\n* Cookiecutter version: 1.5.1\r\n* Template project url: `gh:*`\r\n* Python version: 2.7.13\r\n* Operating System: Linux\r\n\r\n### Description:\r\n\r\ncookiecutter does not honor prefixes anymore.\r\n\r\n### What I've run:\r\n\r\nSimply testing the example from the README doesn't work as expected:\r\n\r\n``` bash\r\n$ cookiecutter gh:audreyr/cookiecutter-pypackage\r\nA valid repository for \"gh:audreyr/cookiecutter-pypackage\" could not be found in the following locations:\r\ngh:audreyr/cookiecutter-pypackage\r\n/home/me/.cookiecutters/gh:audreyr/cookiecutter-pypackage\r\n```\r\nThe same commands using the full repository path works as expected:\r\n\r\n```bash\r\n$ cookiecutter https://github.com/audreyr/cookiecutter-pypackage\r\n```\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"Global configuration handling.\"\"\"\n\nfrom __future__ import unicode_literals\nimport copy\nimport logging\nimport os\nimport io\n\nimport poyo\n\nfrom .exceptions import ConfigDoesNotExistException\nfrom .exceptions import InvalidConfiguration\n\n\nlogger = logging.getLogger(__name__)\n\nUSER_CONFIG_PATH = os.path.expanduser('~/.cookiecutterrc')\n\nBUILTIN_ABBREVIATIONS = {\n    'gh': 'https://github.com/{0}.git',\n    'gl': 'https://gitlab.com/{0}.git',\n    'bb': 'https://bitbucket.org/{0}',\n}\n\nDEFAULT_CONFIG = {\n    'cookiecutters_dir': os.path.expanduser('~/.cookiecutters/'),\n    'replay_dir': os.path.expanduser('~/.cookiecutter_replay/'),\n    'default_context': {},\n    'abbreviations': BUILTIN_ABBREVIATIONS,\n}\n\n\ndef _expand_path(path):\n    \"\"\"Expand both environment variables and user home in the given path.\"\"\"\n    path = os.path.expandvars(path)\n    path = os.path.expanduser(path)\n    return path\n\n\ndef get_config(config_path):\n    \"\"\"Retrieve the config from the specified path, returning a config dict.\"\"\"\n    if not os.path.exists(config_path):\n        raise ConfigDoesNotExistException\n\n    logger.debug('config_path is {0}'.format(config_path))\n    with io.open(config_path, encoding='utf-8') as file_handle:\n        try:\n            yaml_dict = poyo.parse_string(file_handle.read())\n        except poyo.exceptions.PoyoException as e:\n            raise InvalidConfiguration(\n                'Unable to parse YAML file {}. Error: {}'\n                ''.format(config_path, e)\n            )\n\n    config_dict = copy.copy(DEFAULT_CONFIG)\n    config_dict.update(yaml_dict)\n\n    raw_replay_dir = config_dict['replay_dir']\n    config_dict['replay_dir'] = _expand_path(raw_replay_dir)\n\n    raw_cookies_dir = config_dict['cookiecutters_dir']\n    config_dict['cookiecutters_dir'] = _expand_path(raw_cookies_dir)\n\n    return config_dict\n\n\ndef get_user_config(config_file=None, default_config=False):\n    \"\"\"Return the user config as a dict.\n\n    If ``default_config`` is True, ignore ``config_file`` and return default\n    values for the config parameters.\n\n    If a path to a ``config_file`` is given, that is different from the default\n    location, load the user config from that.\n\n    Otherwise look up the config file path in the ``COOKIECUTTER_CONFIG``\n    environment variable. If set, load the config from this path. This will\n    raise an error if the specified path is not valid.\n\n    If the environment variable is not set, try the default config file path\n    before falling back to the default config values.\n    \"\"\"\n    # Do NOT load a config. Return defaults instead.\n    if default_config:\n        return copy.copy(DEFAULT_CONFIG)\n\n    # Load the given config file\n    if config_file and config_file is not USER_CONFIG_PATH:\n        return get_config(config_file)\n\n    try:\n        # Does the user set up a config environment variable?\n        env_config_file = os.environ['COOKIECUTTER_CONFIG']\n    except KeyError:\n        # Load an optional user config if it exists\n        # otherwise return the defaults\n        if os.path.exists(USER_CONFIG_PATH):\n            return get_config(USER_CONFIG_PATH)\n        else:\n            return copy.copy(DEFAULT_CONFIG)\n    else:\n        # There is a config environment variable. Try to load it.\n        # Do not check for existence, so invalid file paths raise an error.\n        return get_config(env_config_file)\n", "path": "cookiecutter/config.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"Global configuration handling.\"\"\"\n\nfrom __future__ import unicode_literals\nimport copy\nimport logging\nimport os\nimport io\n\nimport poyo\n\nfrom .exceptions import ConfigDoesNotExistException\nfrom .exceptions import InvalidConfiguration\n\n\nlogger = logging.getLogger(__name__)\n\nUSER_CONFIG_PATH = os.path.expanduser('~/.cookiecutterrc')\n\nBUILTIN_ABBREVIATIONS = {\n    'gh': 'https://github.com/{0}.git',\n    'gl': 'https://gitlab.com/{0}.git',\n    'bb': 'https://bitbucket.org/{0}',\n}\n\nDEFAULT_CONFIG = {\n    'cookiecutters_dir': os.path.expanduser('~/.cookiecutters/'),\n    'replay_dir': os.path.expanduser('~/.cookiecutter_replay/'),\n    'default_context': {},\n    'abbreviations': BUILTIN_ABBREVIATIONS,\n}\n\n\ndef _expand_path(path):\n    \"\"\"Expand both environment variables and user home in the given path.\"\"\"\n    path = os.path.expandvars(path)\n    path = os.path.expanduser(path)\n    return path\n\n\ndef merge_configs(default, overwrite):\n    \"\"\"Recursively update a dict with the key/value pair of another.\n\n    Dict values that are dictionaries themselves will be updated, whilst\n    preserving existing keys.\n    \"\"\"\n    new_config = copy.deepcopy(default)\n\n    for k, v in overwrite.items():\n        # Make sure to preserve existing items in\n        # nested dicts, for example `abbreviations`\n        if isinstance(v, dict):\n            new_config[k] = merge_configs(default[k], v)\n        else:\n            new_config[k] = v\n\n    return new_config\n\n\ndef get_config(config_path):\n    \"\"\"Retrieve the config from the specified path, returning a config dict.\"\"\"\n    if not os.path.exists(config_path):\n        raise ConfigDoesNotExistException\n\n    logger.debug('config_path is {0}'.format(config_path))\n    with io.open(config_path, encoding='utf-8') as file_handle:\n        try:\n            yaml_dict = poyo.parse_string(file_handle.read())\n        except poyo.exceptions.PoyoException as e:\n            raise InvalidConfiguration(\n                'Unable to parse YAML file {}. Error: {}'\n                ''.format(config_path, e)\n            )\n\n    config_dict = merge_configs(DEFAULT_CONFIG, yaml_dict)\n\n    raw_replay_dir = config_dict['replay_dir']\n    config_dict['replay_dir'] = _expand_path(raw_replay_dir)\n\n    raw_cookies_dir = config_dict['cookiecutters_dir']\n    config_dict['cookiecutters_dir'] = _expand_path(raw_cookies_dir)\n\n    return config_dict\n\n\ndef get_user_config(config_file=None, default_config=False):\n    \"\"\"Return the user config as a dict.\n\n    If ``default_config`` is True, ignore ``config_file`` and return default\n    values for the config parameters.\n\n    If a path to a ``config_file`` is given, that is different from the default\n    location, load the user config from that.\n\n    Otherwise look up the config file path in the ``COOKIECUTTER_CONFIG``\n    environment variable. If set, load the config from this path. This will\n    raise an error if the specified path is not valid.\n\n    If the environment variable is not set, try the default config file path\n    before falling back to the default config values.\n    \"\"\"\n    # Do NOT load a config. Return defaults instead.\n    if default_config:\n        return copy.copy(DEFAULT_CONFIG)\n\n    # Load the given config file\n    if config_file and config_file is not USER_CONFIG_PATH:\n        return get_config(config_file)\n\n    try:\n        # Does the user set up a config environment variable?\n        env_config_file = os.environ['COOKIECUTTER_CONFIG']\n    except KeyError:\n        # Load an optional user config if it exists\n        # otherwise return the defaults\n        if os.path.exists(USER_CONFIG_PATH):\n            return get_config(USER_CONFIG_PATH)\n        else:\n            return copy.copy(DEFAULT_CONFIG)\n    else:\n        # There is a config environment variable. Try to load it.\n        # Do not check for existence, so invalid file paths raise an error.\n        return get_config(env_config_file)\n", "path": "cookiecutter/config.py"}]}