From 038d4ac81f9f078ccc7b7402ab00dd2f1abef233 Mon Sep 17 00:00:00 2001 From: Shahadat Islam Koyel <179203101+ShahadatTest@users.noreply.github.com> Date: Tue, 27 Oct 2026 16:13:48 +0600 Subject: [PATCH] Keep key comparisons and ordering operations case insensitive --- humanfriendly/case.py | 9 +++++++++ humanfriendly/tests.py | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/humanfriendly/case.py b/humanfriendly/case.py index 4c71857..573fc77 100644 --- a/humanfriendly/case.py +++ b/humanfriendly/case.py @@ -74,6 +74,10 @@ def get(self, key, default=None): """Get the value of an existing item.""" return super(CaseInsensitiveDict, self).get(self.coerce_key(key), default) + def move_to_end(self, key, last=True): + """Move an existing key to either end of the dictionary.""" + return super(CaseInsensitiveDict, self).move_to_end(self.coerce_key(key), last=last) + def pop(self, key, default=None): """Remove an item from a case insensitive dictionary.""" return super(CaseInsensitiveDict, self).pop(self.coerce_key(key), default) @@ -155,3 +159,8 @@ def __eq__(self, other): return self._normalized == other.lower() else: return NotImplemented + + def __ne__(self, other): + """Compare inequality using the same lowercase values as equality.""" + equal = self.__eq__(other) + return NotImplemented if equal is NotImplemented else not equal diff --git a/humanfriendly/tests.py b/humanfriendly/tests.py index 72dad99..cedd48b 100644 --- a/humanfriendly/tests.py +++ b/humanfriendly/tests.py @@ -184,6 +184,31 @@ def test_case_insensitive_key(self): mapping[rude] = 2 assert len(mapping) == 1 + def test_case_insensitive_key_inequality(self): + """Keep case-insensitive inequality consistent with equality.""" + lower = CaseInsensitiveKey('content-type') + upper = CaseInsensitiveKey('CONTENT-TYPE') + assert lower == upper + assert not (lower != upper) + assert not (upper != 'content-type') + assert not ('content-type' != upper) + assert upper != 'other' + assert upper != 1 + assert upper.__ne__(object()) is NotImplemented + + def test_case_insensitive_move_to_end(self): + """Coerce string keys before changing their insertion order.""" + obj = CaseInsensitiveDict([('First', 1), ('Second', 2), (3, 3)]) + assert obj.move_to_end('FIRST') is None + assert list(obj) == ['Second', 3, 'First'] + obj.move_to_end('SECOND', last=False) + assert list(obj) == ['Second', 3, 'First'] + obj.move_to_end(3, last=False) + assert list(obj) == [3, 'Second', 'First'] + with self.assertRaises(KeyError): + obj.move_to_end('missing') + assert obj['first'] == 1 + def test_capture_output(self): """Test the CaptureOutput class.""" with CaptureOutput() as capturer: