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 |