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