summaryrefslogtreecommitdiffstats
path: root/ipapython
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2013-09-23 10:46:01 +0200
committerPetr Viktorin <pviktori@redhat.com>2013-09-25 10:13:56 +0200
commita93fc02af6eb50ecb0cfc69174c9f385d60bbbb3 (patch)
tree9c1150ddd8274aad85af93596bd3fba092c75def /ipapython
parent0226064baced57f09b899370752c63cce8009b61 (diff)
downloadfreeipa-a93fc02af6eb50ecb0cfc69174c9f385d60bbbb3.tar.gz
freeipa-a93fc02af6eb50ecb0cfc69174c9f385d60bbbb3.tar.xz
freeipa-a93fc02af6eb50ecb0cfc69174c9f385d60bbbb3.zip
Raise an error when updating CIDict with duplicate keys
Updating a CIDict with data like {'A': 1, 'a': 2} would lead to data loss since only one of the items would get to the CIDict. This can result in non-obvious bugs similar to this one in python-ldap: https://bugzilla.redhat.com/show_bug.cgi?id=1007820 Raise an error in this case; any resolution must be done by the caller.
Diffstat (limited to 'ipapython')
-rw-r--r--ipapython/ipautil.py25
1 files changed, 22 insertions, 3 deletions
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index c5b47f5b4..13d242792 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -455,8 +455,18 @@ class CIDict(dict):
def __getitem__(self, key):
return super(CIDict, self).__getitem__(key.lower())
- def __setitem__(self, key, value):
+ def __setitem__(self, key, value, seen_keys=None):
+ """cidict[key] = value
+
+ The ``seen_keys`` argument is used by ``update()`` to keep track of
+ duplicate keys. It should be an initially empty set that is
+ passed to all calls to __setitem__ that should not set duplicate keys.
+ """
lower_key = key.lower()
+ if seen_keys is not None:
+ if lower_key in seen_keys:
+ raise ValueError('Duplicate key in update: %s' % key)
+ seen_keys.add(lower_key)
self._keys[lower_key] = key
return super(CIDict, self).__setitem__(lower_key, value)
@@ -466,6 +476,14 @@ class CIDict(dict):
return super(CIDict, self).__delitem__(lower_key)
def update(self, new=None, **kwargs):
+ """Update self from dict/iterable new and kwargs
+
+ Functions like ``dict.update()``.
+
+ Neither ``new`` nor ``kwargs`` may contain two keys that only differ in
+ case, as this situation would result in loss of data.
+ """
+ seen = set()
if new:
try:
keys = new.keys
@@ -473,9 +491,10 @@ class CIDict(dict):
self.update(dict(new))
else:
for key in keys():
- self[key] = new[key]
+ self.__setitem__(key, new[key], seen)
+ seen = set()
for key, value in kwargs.iteritems():
- self[key] = value
+ self.__setitem__(key, value, seen)
def __contains__(self, key):
return super(CIDict, self).__contains__(key.lower())