# Buggy code
def apply_config_changes(before_editing, data, kvpairs):
    """Applies config changes specified as a list of key-value pairs.

    Keys are interpreted as dotted paths into the configuration data structure. Except for paths beginning with
    `postgresql.parameters` where rest of the path is used directly to allow for PostgreSQL GUCs containing dots.
    Values are interpreted as YAML values.

    :param before_editing: human representation before editing
    :param data: configuration datastructure
    :param kvpairs: list of strings containing key value pairs separated by =
    :returns tuple of human readable and parsed datastructure after changes
    """
    changed_data = copy.deepcopy(data)

    def set_path_value(config, path, value, prefix=()):
        # Postgresql GUCs can't be nested, but can contain dots so we re-flatten the structure for this case
        if prefix == ("postgresql", "parameters"):
            path = [".".join(path)]

        if len(path) == 1:
            if value is None:
                config.pop(path[0], None)
            else:
                config[path[0]] = value
        else:
            key = path[0]
            if key not in config:
                config[key] = {}
            set_path_value(config[key], path[1:], value, prefix + (key,))
            if config[key] == {}:
                del config[key]

    for pair in kvpairs:
        if not pair or "=" not in pair:
            raise PatroniCtlException("Invalid parameter setting {0}".format(pair))
        key_path, value = pair.split("=", 1)
        set_path_value(changed_data, key_path.strip().split("."), yaml.safe_load(value))

    return format_config_for_editing(changed_data), changed_data


# Traceback (kazoo.exceptions.ConnectionClosedError)
[root@postgres-5-2 ~]# patronictl -c /etc/patroni.yaml edit-config postgres-5
---
+++
@@ -11,4 +11,4 @@
use_pg_rewind: true
use_slots: true
retry_timeout: 10
-ttl: 30
+ttl: 31

Apply these changes? [y/N]: y
2017-07-28 23:27:53,965 - ERROR - Unhandled exception in connection loop
Traceback (most recent call last):
File "/usr/lib/python3.4/site-packages/kazoo/protocol/connection.py", line 541, in _connect_attempt
self._send_request(read_timeout, connect_timeout)
File "/usr/lib/python3.4/site-packages/kazoo/protocol/connection.py", line 445, in _send_request
self._submit(request, connect_timeout, xid)
File "/usr/lib/python3.4/site-packages/kazoo/protocol/connection.py", line 279, in _submit
b += request.serialize()
File "/usr/lib/python3.4/site-packages/kazoo/protocol/serialization.py", line 195, in serialize
b.extend(int_struct.pack(self.version))
struct.error: 'i' format requires -2147483648 <= number <= 2147483647
Exception in thread Thread-3:
Traceback (most recent call last):
File "/usr/lib64/python3.4/threading.py", line 911, in _bootstrap_inner
self.run()
File "/usr/lib64/python3.4/threading.py", line 859, in run
self._target(*self._args, **self._kwargs)
File "/usr/lib/python3.4/site-packages/kazoo/protocol/connection.py", line 471, in zk_loop
if retry(self._connect_loop, retry) is STOP_CONNECTING:
File "/usr/lib/python3.4/site-packages/kazoo/retry.py", line 123, in __call__
return func(*args, **kwargs)
File "/usr/lib/python3.4/site-packages/kazoo/protocol/connection.py", line 488, in _connect_loop
status = self._connect_attempt(host, port, retry)
File "/usr/lib/python3.4/site-packages/kazoo/protocol/connection.py", line 541, in _connect_attempt
self._send_request(read_timeout, connect_timeout)
File "/usr/lib/python3.4/site-packages/kazoo/protocol/connection.py", line 445, in _send_request
self._submit(request, connect_timeout, xid)
File "/usr/lib/python3.4/site-packages/kazoo/protocol/connection.py", line 279, in _submit
b += request.serialize()
File "/usr/lib/python3.4/site-packages/kazoo/protocol/serialization.py", line 195, in serialize
b.extend(int_struct.pack(self.version))
struct.error: 'i' format requires -2147483648 <= number <= 2147483647

2017-07-28 23:27:54,328 - ERROR - set_config_value
Traceback (most recent call last):
File "/usr/lib/python3.4/site-packages/patroni/dcs/zookeeper.py", line 230, in set_config_value
self._client.retry(self._client.set, self.config_path, value.encode('utf-8'), version=index or -1)
File "/usr/lib/python3.4/site-packages/kazoo/client.py", line 273, in _retry
return self._retry.copy()(*args, **kwargs)
File "/usr/lib/python3.4/site-packages/kazoo/retry.py", line 123, in __call__
return func(*args, **kwargs)
File "/usr/lib/python3.4/site-packages/kazoo/client.py", line 1219, in set
return self.set_async(path, value, version).get()
File "/usr/lib/python3.4/site-packages/kazoo/handlers/utils.py", line 72, in get
raise self._exception
kazoo.exceptions.ConnectionClosedError: Connection has been closed
Error: Config modification aborted due to concurrent changes

# Fixed code
def apply_config_changes(before_editing, data, kvpairs):
    """Applies config changes specified as a list of key-value pairs.

    Keys are interpreted as dotted paths into the configuration data structure. Except for paths beginning with
    `postgresql.parameters` where rest of the path is used directly to allow for PostgreSQL GUCs containing dots.
    Values are interpreted as YAML values.

    :param before_editing: human representation before editing
    :param data: configuration datastructure
    :param kvpairs: list of strings containing key value pairs separated by =
    :returns tuple of human readable and parsed datastructure after changes
    """
    changed_data = copy.deepcopy(data)

    def set_path_value(config, path, value, prefix=()):
        # Postgresql GUCs can't be nested, but can contain dots so we re-flatten the structure for this case
        if prefix == ("postgresql", "parameters"):
            path = [".".join(path)]

        key = path[0]
        if len(path) == 1:
            if value is None:
                config.pop(key, None)
            else:
                config[key] = value
        else:
            if not isinstance(config.get(key), dict):
                config[key] = {}
            set_path_value(config[key], path[1:], value, prefix + (key,))
            if config[key] == {}:
                del config[key]

    for pair in kvpairs:
        if not pair or "=" not in pair:
            raise PatroniCtlException("Invalid parameter setting {0}".format(pair))
        key_path, value = pair.split("=", 1)
        set_path_value(changed_data, key_path.strip().split("."), yaml.safe_load(value))

    return format_config_for_editing(changed_data), changed_data