]> Frank Brehm's Git Trees - pixelpark/ldap-migration.git/commitdiff
Starting with lib/ldap_migration/istringset.py
authorFrank Brehm <frank.brehm@pixelpark.com>
Thu, 19 Nov 2020 11:53:32 +0000 (12:53 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Thu, 19 Nov 2020 11:53:32 +0000 (12:53 +0100)
lib/ldap_migration/istringset.py [new file with mode: 0644]

diff --git a/lib/ldap_migration/istringset.py b/lib/ldap_migration/istringset.py
new file mode 100644 (file)
index 0000000..5855d12
--- /dev/null
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@copyright: © 2020 by Frank Brehm, Berlin
+@summary: A module for providing a mutable set with case insensitive sting items.
+"""
+from __future__ import absolute_import
+
+# Standard module
+import logging
+import copy
+
+try:
+    from collections.abc import MutableSet
+except ImportError:
+    from collections import MutableSet
+
+# Third party modules
+
+# Own modules
+from fb_tools.common import pp
+from fb_tools.errors import FbError
+from fb_tools.obj import FbBaseObject
+
+__version__ = '0.1.0'
+
+LOG = logging.getLogger(__name__)
+
+# =============================================================================
+class WrongItemTypeError(TypeError, FbError):
+
+    # -------------------------------------------------------------------------
+    def __init__(self, item):
+
+        self.item = item
+
+    # -------------------------------------------------------------------------
+    def __str__(self):
+
+        msg = "Key {item!r} must be of type 'str', but is of type {cls!r} instead."
+        return msg.format(item=self.item, cls=self.item.__class__.__name__)
+
+
+# =============================================================================
+class WrongCompareSetClassError(TypeError, FbError):
+
+    # -------------------------------------------------------------------------
+    def __init__(self, other):
+
+        self.other_class = other.__class__.__name__
+
+    # -------------------------------------------------------------------------
+    def __str__(self):
+
+        msg = "Object {!r} is not a CaseInsensitiveStringSet object."
+        return msg.format(self.other_class)
+
+
+# =============================================================================
+class CaseInsensitiveStringSet(MutableSet):
+    """
+    A mutable set, where the strings are insensitive strings.
+    The items MUST be of type string!
+    It works like a set.
+    """
+
+    wrong_type_msg = "Item {item!r} must be of type 'str', but is of type {cls!r} instead."
+
+    # -------------------------------------------------------------------------
+    def __init__(self, iterable):
+
+        self._items = []
+
+        for item in iterable:
+
+            if not isinstance(item, str):
+                raise WrongItemTypeError(item)
+
+            if item not in self:
+                self._items.append(item)
+
+    # -------------------------------------------------------------------------
+    # Mandatory methods (ABC methods)
+
+    # -------------------------------------------------------------------------
+    def __iter__(self):
+
+        return iter(self._items)
+
+    # -------------------------------------------------------------------------
+    def __contains__(self, value):
+
+        if not isinstance(value, str):
+            raise WrongItemTypeError(value)
+
+        for item in self._items:
+            if item.lower() == value.lower():
+                return True
+
+        return value in self.elements
+
+    # -------------------------------------------------------------------------
+    def __len__(self):
+        return len(self._items)
+
+    # ------------------------------------------------------------------------- 
+    def add(self, value):
+
+        if not isinstance(value, str):
+            raise WrongItemTypeError(value)
+
+        if value in self:
+
+            index = 0
+            for item in self._items:
+                if item.lower() == value.lower():
+                    if item != value:
+                        self._items[index] = value
+                    break
+                index += 1
+
+        else:
+            self._items.append(value)
+
+    # -------------------------------------------------------------------------
+    def discard(self, value):
+
+        index = 0
+        for item in self._items:
+            if item.lower() == value.lower():
+                del self._items[index]
+                break
+            index += 1
+
+    # -------------------------------------------------------------------------
+    # Nice to have methods
+
+    # -------------------------------------------------------------------------
+    def isdisjoint(self, other):
+
+        if not isinstance(other, CaseInsensitiveStringSet):
+            raise WrongCompareSetClassError(other)
+
+        for item in self._items:
+            if item in other:
+                return False
+
+        return True
+
+    # -------------------------------------------------------------------------
+    def issubset(self, other):
+
+        if not isinstance(other, CaseInsensitiveStringSet):
+            raise WrongCompareSetClassError(other)
+
+        for item in self._items:
+            if item not in other:
+                return False
+
+        return True
+
+    # -------------------------------------------------------------------------
+    def __le__(self, other):
+
+        if not isinstance(other, CaseInsensitiveStringSet):
+            raise WrongCompareSetClassError(other)
+
+        return self.issubset(other)
+
+    # -------------------------------------------------------------------------
+    def __eq__(self, other):
+
+        if not isinstance(other, CaseInsensitiveStringSet):
+            raise WrongCompareSetClassError(other)
+
+        if len(self) != len(other):
+            return False
+
+        for item in self._items:
+            if item not in other:
+                return False
+
+        return True
+
+    # -------------------------------------------------------------------------
+    def __ne__(self, other):
+
+        if not isinstance(other, CaseInsensitiveStringSet):
+            raise WrongCompareSetClassError(other)
+
+        if self == other:
+            return False
+        return True
+
+    # -------------------------------------------------------------------------
+    def __lt__(self, other):
+
+        if not isinstance(other, CaseInsensitiveStringSet):
+            raise WrongCompareSetClassError(other)
+
+        ret = True
+        for item in self._items:
+            if item not in other:
+                ret = False
+        if ret:
+            if len(self) != len(other):
+                return True
+        return False
+
+
+# =============================================================================
+if __name__ == "__main__":
+
+    pass
+
+# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list