| | 245 | |
| | 246 | class CaseInsensitiveDict(dict): |
| | 247 | """ |
| | 248 | A dictionary which uses case-insensitive keys. Original case is preserved, |
| | 249 | but can be read or overwritten by the same key of any mix of upper and |
| | 250 | lower case. |
| | 251 | """ |
| | 252 | def __init__(self, *kw, **kwargs): |
| | 253 | super(CaseInsensitiveDict, self).__init__(*kw, **kwargs) |
| | 254 | # Set up case insensitive keys dict for future reference. |
| | 255 | keys = {} |
| | 256 | for key in self.keys(): |
| | 257 | if isinstance(key, basestring): |
| | 258 | keys[key.lower()] = key |
| | 259 | self._case_insensitive_keys = keys |
| | 260 | |
| | 261 | def _get_case_sensitive_key(self, key): |
| | 262 | if isinstance(key, basestring): |
| | 263 | key = self._case_insensitive_keys.get(key.lower(), key) |
| | 264 | return key |
| | 265 | |
| | 266 | def __getitem__(self, key): |
| | 267 | key = self._get_case_sensitive_key(key) |
| | 268 | return super(CaseInsensitiveDict, self).__getitem__(key) |
| | 269 | |
| | 270 | def __setitem__(self, key, value): |
| | 271 | if isinstance(key, basestring): |
| | 272 | key_lower = key.lower() |
| | 273 | if key_lower in self._case_insensitive_keys.keys(): |
| | 274 | # Delete old key (since it may be a different case). |
| | 275 | old_key = self._case_insensitive_keys[key_lower] |
| | 276 | super(CaseInsensitiveDict, self).__delitem__(old_key) |
| | 277 | # Save new key in case insensitive dict. |
| | 278 | self._case_insensitive_keys[key_lower] = key |
| | 279 | return super(CaseInsensitiveDict, self).__setitem__(key, value) |
| | 280 | |
| | 281 | def __delitem__(self, key): |
| | 282 | key = self._get_case_sensitive_key(key) |
| | 283 | if isinstance(key, basestring): |
| | 284 | # Delete key from case insensitive dict. |
| | 285 | del self._case_insensitive_keys[key.lower()] |
| | 286 | return super(CaseInsensitiveDict, self).__delitem__(key) |
| | 287 | |
| | 288 | def __contains__(self, key): |
| | 289 | key = self._get_case_sensitive_key(key) |
| | 290 | return super(CaseInsensitiveDict, self).__contains__(key) |
| | 291 | |
| | 292 | def get(self, key, default=None): |
| | 293 | key = self._get_case_sensitive_key(key) |
| | 294 | return super(CaseInsensitiveDict, self).get(key, default) |
| | 295 | |
| | 296 | def has_key(self, key): |
| | 297 | key = self._get_case_sensitive_key(key) |
| | 298 | return super(CaseInsensitiveDict, self).has_key(key) |
| | 299 | |
| | 300 | def pop(self, key): |
| | 301 | key = self._get_case_sensitive_key(key) |
| | 302 | # Delete key from case insensitive dict. Could raise KeyError, but |
| | 303 | # that's what is raised on a non-existant .pop(key) anyway. |
| | 304 | del self._case_insensitive_keys[key.lower()] |
| | 305 | return super(CaseInsensitiveDict, self).pop(key) |
| | 306 | |
| | 307 | def update(self, dict=None, **kwargs): |
| | 308 | if dict is None: |
| | 309 | # Handle it the alternate way introduced in Python 2.4 |
| | 310 | dict = kwargs |
| | 311 | if dict: |
| | 312 | # Check for keys in new dict which may differ to the current keys. |
| | 313 | for key in dict.keys(): |
| | 314 | existing_key = self._get_case_sensitive_key(key) |
| | 315 | if key != existing_key: |
| | 316 | # Delete existing key (with different case). |
| | 317 | del self[existing_key] |
| | 318 | # Change existing case insensitive key to match new key case. |
| | 319 | self._case_insensitive_keys[key.lower()] = key |
| | 320 | return super(CaseInsensitiveDict, self).update(dict) |
| | 321 | |
| | 322 | def clear(self): |
| | 323 | # Reset case insensitive dict |
| | 324 | self._case_insensitive_keys = {} |
| | 325 | return super(CaseInsensitiveDict, self).clear() |
| | 326 | |
| | 327 | def setdefault(self, key, default=None): |
| | 328 | if not self.has_key(key): |
| | 329 | # Update case insensitive dict, since dict.setdefault() doesn't |
| | 330 | # use internal __setitem__ method. |
| | 331 | self._case_insensitive_keys[key.lower()] = key |
| | 332 | return super(CaseInsensitiveDict, self).setdefault(key, default) |