Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/humanfriendly/case.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
| author | shellac |
|---|---|
| date | Thu, 14 May 2020 14:56:58 -0400 |
| parents | 26e78fe6e8c4 |
| children |
comparison
equal
deleted
inserted
replaced
| 1:75ca89e9b81c | 2:6af9afd405e9 |
|---|---|
| 1 # Human friendly input/output in Python. | |
| 2 # | |
| 3 # Author: Peter Odding <peter@peterodding.com> | |
| 4 # Last Change: April 19, 2020 | |
| 5 # URL: https://humanfriendly.readthedocs.io | |
| 6 | |
| 7 """ | |
| 8 Simple case insensitive dictionaries. | |
| 9 | |
| 10 The :class:`CaseInsensitiveDict` class is a dictionary whose string keys | |
| 11 are case insensitive. It works by automatically coercing string keys to | |
| 12 :class:`CaseInsensitiveKey` objects. Keys that are not strings are | |
| 13 supported as well, just without case insensitivity. | |
| 14 | |
| 15 At its core this module works by normalizing strings to lowercase before | |
| 16 comparing or hashing them. It doesn't support proper case folding nor | |
| 17 does it support Unicode normalization, hence the word "simple". | |
| 18 """ | |
| 19 | |
| 20 # Standard library modules. | |
| 21 import collections | |
| 22 | |
| 23 try: | |
| 24 # Python >= 3.3. | |
| 25 from collections.abc import Iterable, Mapping | |
| 26 except ImportError: | |
| 27 # Python 2.7. | |
| 28 from collections import Iterable, Mapping | |
| 29 | |
| 30 # Modules included in our package. | |
| 31 from humanfriendly.compat import basestring, unicode | |
| 32 | |
| 33 # Public identifiers that require documentation. | |
| 34 __all__ = ("CaseInsensitiveDict", "CaseInsensitiveKey") | |
| 35 | |
| 36 | |
| 37 class CaseInsensitiveDict(collections.OrderedDict): | |
| 38 | |
| 39 """ | |
| 40 Simple case insensitive dictionary implementation (that remembers insertion order). | |
| 41 | |
| 42 This class works by overriding methods that deal with dictionary keys to | |
| 43 coerce string keys to :class:`CaseInsensitiveKey` objects before calling | |
| 44 down to the regular dictionary handling methods. While intended to be | |
| 45 complete this class has not been extensively tested yet. | |
| 46 """ | |
| 47 | |
| 48 def __init__(self, other=None, **kw): | |
| 49 """Initialize a :class:`CaseInsensitiveDict` object.""" | |
| 50 # Initialize our superclass. | |
| 51 super(CaseInsensitiveDict, self).__init__() | |
| 52 # Handle the initializer arguments. | |
| 53 self.update(other, **kw) | |
| 54 | |
| 55 def coerce_key(self, key): | |
| 56 """ | |
| 57 Coerce string keys to :class:`CaseInsensitiveKey` objects. | |
| 58 | |
| 59 :param key: The value to coerce (any type). | |
| 60 :returns: If `key` is a string then a :class:`CaseInsensitiveKey` | |
| 61 object is returned, otherwise the value of `key` is | |
| 62 returned unmodified. | |
| 63 """ | |
| 64 if isinstance(key, basestring): | |
| 65 key = CaseInsensitiveKey(key) | |
| 66 return key | |
| 67 | |
| 68 @classmethod | |
| 69 def fromkeys(cls, iterable, value=None): | |
| 70 """Create a case insensitive dictionary with keys from `iterable` and values set to `value`.""" | |
| 71 return cls((k, value) for k in iterable) | |
| 72 | |
| 73 def get(self, key, default=None): | |
| 74 """Get the value of an existing item.""" | |
| 75 return super(CaseInsensitiveDict, self).get(self.coerce_key(key), default) | |
| 76 | |
| 77 def pop(self, key, default=None): | |
| 78 """Remove an item from a case insensitive dictionary.""" | |
| 79 return super(CaseInsensitiveDict, self).pop(self.coerce_key(key), default) | |
| 80 | |
| 81 def setdefault(self, key, default=None): | |
| 82 """Get the value of an existing item or add a new item.""" | |
| 83 return super(CaseInsensitiveDict, self).setdefault(self.coerce_key(key), default) | |
| 84 | |
| 85 def update(self, other=None, **kw): | |
| 86 """Update a case insensitive dictionary with new items.""" | |
| 87 if isinstance(other, Mapping): | |
| 88 # Copy the items from the given mapping. | |
| 89 for key, value in other.items(): | |
| 90 self[key] = value | |
| 91 elif isinstance(other, Iterable): | |
| 92 # Copy the items from the given iterable. | |
| 93 for key, value in other: | |
| 94 self[key] = value | |
| 95 elif other is not None: | |
| 96 # Complain about unsupported values. | |
| 97 msg = "'%s' object is not iterable" | |
| 98 type_name = type(value).__name__ | |
| 99 raise TypeError(msg % type_name) | |
| 100 # Copy the keyword arguments (if any). | |
| 101 for key, value in kw.items(): | |
| 102 self[key] = value | |
| 103 | |
| 104 def __contains__(self, key): | |
| 105 """Check if a case insensitive dictionary contains the given key.""" | |
| 106 return super(CaseInsensitiveDict, self).__contains__(self.coerce_key(key)) | |
| 107 | |
| 108 def __delitem__(self, key): | |
| 109 """Delete an item in a case insensitive dictionary.""" | |
| 110 return super(CaseInsensitiveDict, self).__delitem__(self.coerce_key(key)) | |
| 111 | |
| 112 def __getitem__(self, key): | |
| 113 """Get the value of an item in a case insensitive dictionary.""" | |
| 114 return super(CaseInsensitiveDict, self).__getitem__(self.coerce_key(key)) | |
| 115 | |
| 116 def __setitem__(self, key, value): | |
| 117 """Set the value of an item in a case insensitive dictionary.""" | |
| 118 return super(CaseInsensitiveDict, self).__setitem__(self.coerce_key(key), value) | |
| 119 | |
| 120 | |
| 121 class CaseInsensitiveKey(unicode): | |
| 122 | |
| 123 """ | |
| 124 Simple case insensitive dictionary key implementation. | |
| 125 | |
| 126 The :class:`CaseInsensitiveKey` class provides an intentionally simple | |
| 127 implementation of case insensitive strings to be used as dictionary keys. | |
| 128 | |
| 129 If you need features like Unicode normalization or proper case folding | |
| 130 please consider using a more advanced implementation like the :pypi:`istr` | |
| 131 package instead. | |
| 132 """ | |
| 133 | |
| 134 def __new__(cls, value): | |
| 135 """Create a :class:`CaseInsensitiveKey` object.""" | |
| 136 # Delegate string object creation to our superclass. | |
| 137 obj = unicode.__new__(cls, value) | |
| 138 # Store the lowercased string and its hash value. | |
| 139 normalized = obj.lower() | |
| 140 obj._normalized = normalized | |
| 141 obj._hash_value = hash(normalized) | |
| 142 return obj | |
| 143 | |
| 144 def __hash__(self): | |
| 145 """Get the hash value of the lowercased string.""" | |
| 146 return self._hash_value | |
| 147 | |
| 148 def __eq__(self, other): | |
| 149 """Compare two strings as lowercase.""" | |
| 150 if isinstance(other, CaseInsensitiveKey): | |
| 151 # Fast path (and the most common case): Comparison with same type. | |
| 152 return self._normalized == other._normalized | |
| 153 elif isinstance(other, unicode): | |
| 154 # Slow path: Comparison with strings that need lowercasing. | |
| 155 return self._normalized == other.lower() | |
| 156 else: | |
| 157 return NotImplemented |
