laforge has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/python/pyosmocom/+/38023?usp=email )


Change subject: Introduce a new 'hexstr' type to represent hex-strings
......................................................................

Introduce a new 'hexstr' type to represent hex-strings

hexstr differs from str in that comparisons are case-insensitive, and it offers 
encoding-free
conversion from hexstr to bytes and vice-versa.

Change-Id: I16c0df809bc11ec0f98e8ade404f9b82072e3a06
---
M src/osmocom/utils.py
A tests/test_utils.py
2 files changed, 88 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/python/pyosmocom 
refs/changes/23/38023/1

diff --git a/src/osmocom/utils.py b/src/osmocom/utils.py
index cbcdd46..96476f1 100644
--- a/src/osmocom/utils.py
+++ b/src/osmocom/utils.py
@@ -138,6 +138,36 @@
     except:
         return False

+class hexstr(str):
+    """Class derived from 'str', represeting a string of hexadecimal digits. 
It differs in that
+    comparisons are case-insensitive, and it offers encoding-free conversion 
from hexstr to bytes
+    and vice-versa."""
+    def __new__(cls, s: str):
+        if not all(c in string.hexdigits for c in s):
+            raise ValueError('Input must be hexadecimal digits only')
+        # store as lower case digits
+        return super().__new__(cls, s.lower())
+
+    def __eq__(self, other):
+        # make sure comparison is done case-insensitive
+        return str(self) == other.lower()
+
+    def __getitem__(self, val):
+        # make sure slicing a hexstr will return a hexstr
+        return hexstr(super().__getitem__(val))
+
+    def to_bytes(self):
+        """return hex-string converted to bytes"""
+        s = str(self)
+        if len(s) & 1:
+            raise ValueError('Cannot convert hex string with odd number of 
digits')
+        return h2b(s)
+
+    @classmethod
+    def from_bytes(cls, bt: bytes) -> 'hexstr':
+        """instantiate hex-string from bytes"""
+        return cls(b2h(bt))
+
 #########################################################################
 # ARGPARSE HELPERS
 #########################################################################
diff --git a/tests/test_utils.py b/tests/test_utils.py
new file mode 100755
index 0000000..8e4732f
--- /dev/null
+++ b/tests/test_utils.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+
+# (C) 2022 by Harald Welte <[email protected]>
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from osmocom.utils import *
+
+class TestHexstr(unittest.TestCase):
+    def test_cmp(self):
+        s = hexstr('aBcD')
+        self.assertEqual(s, 'abcd')
+        self.assertEqual(s, 'ABCD')
+        self.assertEqual(s, 'AbCd')
+        self.assertEqual(s, hexstr('AbCd'))
+
+    def test_tobytes(self):
+        s = hexstr('aBcDeF')
+        self.assertEqual(s.to_bytes(), b'\xab\xcd\xef')
+
+    def test_tobytes_odd(self):
+        s2 = hexstr('aBc')
+        with self.assertRaises(ValueError):
+            s2.to_bytes()
+
+    def test_frombytes(self):
+        s = hexstr.from_bytes(b'\x01\x02\xaa')
+        self.assertEqual(s, '0102aa')
+
+    def test_slice(self):
+        s = hexstr('abcdef')
+        slice1 = s[-2:]
+        self.assertTrue(isinstance(slice1, hexstr))
+        self.assertEqual(slice1, 'ef')
+        slice2 = s[1]
+        self.assertTrue(isinstance(slice2, hexstr))
+        self.assertEqual(slice2, 'b')
+
+    def test_str_lower(self):
+        self.assertEqual(str(hexstr('ABCD')), 'abcd')
+
+
+if __name__ == "__main__":
+       unittest.main()

--
To view, visit https://gerrit.osmocom.org/c/python/pyosmocom/+/38023?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: python/pyosmocom
Gerrit-Branch: master
Gerrit-Change-Id: I16c0df809bc11ec0f98e8ade404f9b82072e3a06
Gerrit-Change-Number: 38023
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <[email protected]>

Reply via email to