From: Frank Brehm Date: Thu, 19 Nov 2020 11:53:32 +0000 (+0100) Subject: Starting with lib/ldap_migration/istringset.py X-Git-Url: https://git.uhu-banane.net/?a=commitdiff_plain;h=a13e3177d630d7dd29e36741848c20411addb4bb;p=pixelpark%2Fldap-migration.git Starting with lib/ldap_migration/istringset.py --- diff --git a/lib/ldap_migration/istringset.py b/lib/ldap_migration/istringset.py new file mode 100644 index 0000000..5855d12 --- /dev/null +++ b/lib/ldap_migration/istringset.py @@ -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