diff options
-rw-r--r-- | ipalib/dn.py | 262 | ||||
-rw-r--r-- | tests/test_ipalib/test_dn.py | 89 |
2 files changed, 211 insertions, 140 deletions
diff --git a/ipalib/dn.py b/ipalib/dn.py index 47c66198e..1311b6ae0 100644 --- a/ipalib/dn.py +++ b/ipalib/dn.py @@ -19,7 +19,6 @@ from ldap.dn import str2dn, dn2str from ldap import DECODING_ERROR -from copy import deepcopy import sys __all__ = ['AVA', 'RDN', 'DN'] @@ -392,7 +391,7 @@ if container_dn in dn: # (e.g. cmp()). The general rule is for objects supporting multiple # values first their lengths are compared, then if the lengths match # the respective components of each are pair-wise compared until one -# is discovered to be non-equal +# is discovered to be non-equal. The comparision is case insensitive. Concatenation and In-Place Addition: @@ -412,13 +411,35 @@ manipulate these objects. ''' +def _adjust_indices(start, end, length): + 'helper to fixup start/end slice values' + + if end > length: + end = length + elif end < 0: + end += length + if end < 0: + end = 0 + + if start < 0: + start += length + if start < 0: + start = 0 + + return start, end + class AVA(object): ''' + AVA(arg0, ...) + An AVA is an LDAP Attribute Value Assertion. It is convenient to think of AVA's as a <attr,value> pair. AVA's are members of RDN's (Relative Distinguished Name). - The AVA constructor may be invoked with any of the following methods: + The AVA constructor is passed a sequence of args and a set of + keyword parameters used for configuration. + + The arg sequence may be: 1) With 2 string (or unicode) arguments, the first argument will be the attr, the 2nd the value. @@ -454,14 +475,16 @@ class AVA(object): AVA objects support equality testing and comparsion (e.g. cmp()). When they are compared the attr is compared first, if the 2 attr's are equal then the - values are compared. + values are compared. The comparision is case insensitive (because attr's map + to numeric OID's and their values derive from from the 'name' atribute type + (OID 2.5.4.41) whose EQUALITY MATCH RULE is caseIgnoreMatch. The str method of an AVA returns the string representation in RFC 4514 DN syntax with proper escaping. ''' flags = 0 - def __init__(self, *args): + def __init__(self, *args, **kwds): if len(args) == 1: arg = args[0] if isinstance(arg, basestring): @@ -496,42 +519,84 @@ class AVA(object): if not isinstance(value, basestring): raise TypeError("value must be basestring, got %s instead" % value.__class__.__name__) - self.attr = attr.decode('utf-8') - self.value = value.decode('utf-8') + attr = attr.decode('utf-8') + value = value.decode('utf-8') + + self._attr = attr + self._value = value + + def _get_attr(self): + return self._attr + + def _set_attr(self, new_attr): + if not isinstance(new_attr, basestring): + raise TypeError("attr must be basestring, got %s instead" % new_attr.__class__.__name__) + + self._attr = new_attr + attr = property(_get_attr, _set_attr) + + def _get_value(self): + return self._value + + def _set_value(self, new_value): + if not isinstance(new_value, basestring): + raise TypeError("value must be basestring, got %s instead" % new_value.__class__.__name__) + + self._value = new_value + + value = property(_get_value, _set_value) def _to_openldap(self): - return [[(self.attr.encode('utf-8'), self.value.encode('utf-8'), self.flags)]] + return [[(self._attr.encode('utf-8'), self._value.encode('utf-8'), self.flags)]] def __str__(self): return dn2str(self._to_openldap()) def __getitem__(self, key): if isinstance(key, basestring): - if key == self.attr: - return self.value + if key == self._attr: + return self._value raise KeyError("\"%s\" not found in %s" % (key, self.__str__())) else: raise TypeError("unsupported type for AVA indexing, must be basestring; not %s" % \ (key.__class__.__name__)) def __eq__(self, other): + ''' + The attr comparison is case insensitive because attr is + really an LDAP attribute type which means it's specified with + an OID (dotted number) and not a string. Since OID's are + numeric the human readable name which maps to the OID is not + significant in case. + + The value comparison is also case insensitive because the all + attribute types used in a DN are derived from the 'name' + atribute type (OID 2.5.4.41) whose EQUALITY MATCH RULE is + caseIgnoreMatch. + ''' if not isinstance(other, self.__class__): raise TypeError("expected AVA but got %s" % (other.__class__.__name__)) - return self.attr == other.attr and self.value == other.value + return self._attr.lower() == other.attr.lower() and \ + self._value.lower() == other.value.lower() def __cmp__(self, other): + 'comparision is case insensitive, see __eq__ doc for explanation' + if not isinstance(other, self.__class__): raise TypeError("expected AVA but got %s" % (other.__class__.__name__)) - result = cmp(self.attr, other.attr) - if result != 0: return result - result = cmp(self.value, other.value) + result = cmp(self._attr.lower(), other.attr.lower()) + if result != 0: + return result + result = cmp(self._value.lower(), other.value.lower()) return result class RDN(object): ''' + RDN(arg0, ..., first_key_match=True) + An RDN is a LDAP Relative Distinguished Name. RDN's are members of DN's (Distinguished Name). An RDN contains 1 or more AVA's. If the RDN contains more than one AVA it is said to be a multi-valued RDN. When an RDN is @@ -542,13 +607,12 @@ class RDN(object): within an RDN). Single valued RDN's are the norm and thus the RDN constructor has simple syntax for them. - The RDN constructor may be invoked in a variety of different ways. + The RDN constructor is passed a sequence of args and a set of + keyword parameters used for configuration. + + The constructor iterates though the sequence and adds AVA's to the RDN. - * When two adjacent string (or unicode) argument appear together in the - argument list they are taken to be the <attr,value> pair of an AVA. An AVA - object is constructed and inserted into the RDN. Multiple pairs of strings - arguments may appear in the argument list, each pair adds one additional AVA - to the RDN. + The arg sequence may be: * A 2-valued tuple or list denotes the <attr,value> pair of an AVA. The first member is the attr and the second member is the value, both members @@ -562,28 +626,26 @@ class RDN(object): more AVA <attr,value> pairs. The parsing recognizes the DN syntax escaping rules. - Note, a DN syntax argument is distguished from AVA string pairs by testing - to see if two strings appear adjacent in the argument list, if so those two - strings are interpretted as an <attr,value> AVA pair and consumed. + * A AVA object, the AVA will be copied into the new RDN respecting + the constructors keyword configuration parameters. - * A AVA object. Each AVA object in the argument list will be added to the RDN. + * A RDN object, the AVA's in the RDN are copied into the new RDN + respecting the constructors keyword configuration parameters. Single AVA Examples: - RDN('cn', 'Bob') # 2 adjacent strings yield 1 AVA RDN(('cn', 'Bob')) # tuple yields 1 AVA RDN('cn=Bob') # DN syntax with 1 AVA RDN(AVA('cn', 'Bob')) # AVA object adds 1 AVA Multiple AVA Examples: - RDN('cn', 'Bob', 'ou', 'people') # 2 strings pairs yield 2 AVA's RDN(('cn', 'Bob'),('ou', 'people')) # 2 tuples yields 2 AVA's RDN('cn=Bob+ou=people') # DN syntax with 2 AVA's RDN(AVA('cn', 'Bob'),AVA('ou', 'people')) # 2 AVA objects adds 2 AVA's - RDN('cn', 'Bob', "ou=people') # 3 strings, 1st two strings form 1 AVA - # 3rd string DN syntax for 1 AVA, - # adds 2 AVA's in total + RDN(('cn', 'Bob'), 'ou=people') # 2 args, 1st tuple forms 1 AVA, + # 2nd DN syntax string adds 1 AVA, + # 2 AVA's in total Note: The RHS of a slice assignment is interpreted exactly in the same manner as the constructor argument list (see above examples). @@ -613,7 +675,7 @@ class RDN(object): and value properties return the attr and value properties of the first AVA in the RDN, for example: - rdn = RDN('cn', 'Bob') # rdn has 1 AVA whose attr == 'cn' and value == 'Bob' + rdn = RDN(('cn', 'Bob')) # rdn has 1 AVA whose attr == 'cn' and value == 'Bob' len(rdn) -> 1 rdn.attr -> u'cn' # exactly equivalent to rdn[0].attr rdn.value -> u'Bob' # exactly equivalent to rdn[0].value @@ -644,14 +706,22 @@ class RDN(object): flags = 0 - def __init__(self, *args): - self.first_key_match = True + def __init__(self, *args, **kwds): + self.first_key_match = kwds.get('first_key_match', True) self.avas = self._avas_from_sequence(args) self.avas.sort() def _ava_from_value(self, value): if isinstance(value, AVA): - return deepcopy(value) + return AVA(value.attr, value.value) + elif isinstance(value, RDN): + avas = [] + for ava in value.avas: + avas.append(AVA(ava.attr, ava.value)) + if len(avas) == 1: + return avas[0] + else: + return avas elif isinstance(value, basestring): try: rdns = str2dn(value.encode('utf-8')) @@ -679,22 +749,12 @@ class RDN(object): def _avas_from_sequence(self, seq): avas = [] - i = 0 - while i < len(seq): - if i+1 < len(seq) and \ - isinstance(seq[i], basestring) and \ - isinstance(seq[i+1], basestring): - ava = AVA(seq[i], seq[i+1]) - avas.append(ava) - i += 2 + for item in seq: + ava = self._ava_from_value(item) + if isinstance(ava, list): + avas.extend(ava) else: - arg = seq[i] - ava = self._ava_from_value(arg) - if isinstance(ava, list): - avas.extend(ava) - else: - avas.append(ava) - i += 1 + avas.append(ava) return avas def _to_openldap(self): @@ -753,7 +813,8 @@ class RDN(object): if key == self.avas[i].attr: found = True self.avas[i] = new_ava - if self.first_key_match: break + if self.first_key_match: + break i += 1 if not found: raise KeyError("\"%s\" not found in %s" % (key, self.__str__())) @@ -805,25 +866,27 @@ class RDN(object): raise TypeError("expected RDN but got %s" % (other.__class__.__name__)) result = cmp(len(self), len(other)) - if result != 0: return result + if result != 0: + return result i = 0 while i < len(self): result = cmp(self[i], other[i]) - if result != 0: return result + if result != 0: + return result i += 1 return 0 def __add__(self, other): - result = deepcopy(self) - if isinstance(other, self.__class__): + result = RDN(self, first_key_match=self.first_key_match) + if isinstance(other, RDN): for ava in other.avas: - result.avas.append(deepcopy(ava)) + result.avas.append(AVA(ava.attr, ava.value)) elif isinstance(other, AVA): - result.avas.append(deepcopy(other)) + result.avas.append(AVA(other.attr, other.value)) elif isinstance(other, basestring): rdn = RDN(other) for ava in rdn.avas: - result.avas.append(deepcopy(ava)) + result.avas.append(AVA(ava.attr, ava.value)) else: raise TypeError("expected RDN, AVA or basestring but got %s" % (other.__class__.__name__)) @@ -831,15 +894,15 @@ class RDN(object): return result def __iadd__(self, other): - if isinstance(other, self.__class__): + if isinstance(other, RDN): for ava in other.avas: - self.avas.append(deepcopy(ava)) + self.avas.append(AVA(ava.attr, ava.value)) elif isinstance(other, AVA): - self.avas.append(deepcopy(other)) + self.avas.append(AVA(other.attr, other.value)) elif isinstance(other, basestring): rdn = RDN(other) for ava in rdn.avas: - self.avas.append(deepcopy(ava)) + self.avas.append(AVA(ava.attr, ava.value)) else: raise TypeError("expected RDN, AVA or basestring but got %s" % (other.__class__.__name__)) @@ -848,11 +911,17 @@ class RDN(object): class DN(object): ''' + DN(arg0, ..., first_key_match=True) + A DN is a LDAP Distinguished Name. A DN is an ordered sequence of RDN's. - The DN constructor accepts a sequence. The constructor iterates - through the sequence and adds the RDN's it finds in order to the - DN object. Each item in the sequence may be: + The DN constructor is passed a sequence of args and a set of + keyword parameters used for configuration. normalize means the + attr and value will be converted to lower case. + + The constructor iterates through the sequence and adds the RDN's + it finds in order to the DN object. Each item in the sequence may + be: * A 2-valued tuple or list. The first member is the attr and the second member is the value of an RDN, both members must be @@ -866,11 +935,12 @@ class DN(object): to yield one or more RDN's which will be appended in order to the DN. The parsing recognizes the DN syntax escaping rules. - * A RDN object. Each RDN object in the argument list will be - appended to the DN in order. + * A RDN object, the RDN will copied respecting the constructors + keyword configuration parameters and appended in order. - * A DN object. Each DN object in the argument list will append in order - it's RDN's to the DN. + * A DN object, the RDN's in the DN are copied respecting the + constructors keyword configuration parameters and appended in + order. Single DN Examples: @@ -972,17 +1042,18 @@ class DN(object): flags = 0 - def __init__(self, *args): + def __init__(self, *args, **kwds): + self.first_key_match = kwds.get('first_key_match', True) self.first_key_match = True self.rdns = self._rdns_from_sequence(args) def _rdn_from_value(self, value): if isinstance(value, RDN): - return deepcopy(value) + return RDN(value, first_key_match=self.first_key_match) elif isinstance(value, DN): rdns = [] for rdn in value.rdns: - rdns.append(deepcopy(rdn)) + rdns.append(RDN(rdn, first_key_match=self.first_key_match)) if len(rdns) == 1: return rdns[0] else: @@ -995,7 +1066,7 @@ class DN(object): avas = [] for ava_tuple in rdn_list: avas.append(AVA(ava_tuple[0], ava_tuple[1])) - rdn = RDN(*avas) + rdn = RDN(*avas, first_key_match=self.first_key_match) rdns.append(rdn) except DECODING_ERROR: raise ValueError("malformed RDN string = \"%s\"" % value) @@ -1006,7 +1077,7 @@ class DN(object): elif isinstance(value, (tuple, list)): if len(value) != 2: raise ValueError("tuple or list must be 2-valued, not \"%s\"" % (rdn)) - rdn = RDN(value) + rdn = RDN(value, first_key_match=self.first_key_match) return rdn else: raise TypeError("must be str,unicode,tuple, or RDN, got %s instead" % \ @@ -1098,7 +1169,8 @@ class DN(object): raise TypeError("expected DN but got %s" % (other.__class__.__name__)) result = cmp(len(self), len(other)) - if result != 0: return result + if result != 0: + return result return self._cmp_sequence(other, 0, len(self)) def _cmp_sequence(self, pattern, self_start, pat_len): @@ -1106,35 +1178,36 @@ class DN(object): pat_idx = 0 while pat_idx < pat_len: result = cmp(self[self_idx], pattern[pat_idx]) - if result != 0: return result + if result != 0: + return result self_idx += 1 pat_idx += 1 return 0 def __add__(self, other): - result = deepcopy(self) + result = DN(self, first_key_match=self.first_key_match) if isinstance(other, self.__class__): for rdn in other.rdns: - result.rdns.append(deepcopy(rdn)) + result.rdns.append(RDN(rdn, first_key_match=self.first_key_match)) elif isinstance(other, RDN): - result.rdns.append(deepcopy(other)) + result.rdns.append(RDN(other, first_key_match=self.first_key_match)) elif isinstance(other, basestring): - dn = DN(other) + dn = DN(other, first_key_match=self.first_key_match) for rdn in dn.rdns: - result.rdns.append(deepcopy(rdn)) + result.rdns.append(rdn) else: raise TypeError("expected DN, RDN or basestring but got %s" % (other.__class__.__name__)) return result def __iadd__(self, other): - if isinstance(other, self.__class__): + if isinstance(other, DN): for rdn in other.rdns: - self.rdns.append(deepcopy(rdn)) + self.rdns.append(RDN(rdn, first_key_match=self.first_key_match)) elif isinstance(other, RDN): - self.rdns.append(deepcopy(other)) + self.rdns.append(RDN(other, first_key_match=self.first_key_match)) elif isinstance(other, basestring): - dn = DN(other) + dn = DN(other, first_key_match=self.first_key_match) self.__iadd__(dn) else: raise TypeError("expected DN, RDN or basestring but got %s" % (other.__class__.__name__)) @@ -1174,23 +1247,6 @@ class DN(object): return self._tailmatch(suffix, start, end, +1) - def _adjust_indices(self, start, end, length): - 'helper to fixup start/end slice values' - - if end > length: - end = length - elif end < 0: - end += length - if end < 0: - end = 0 - - if start < 0: - start += length - if start < 0: - start = 0 - - return start, end - def _tailmatch(self, pattern, start, end, direction): ''' Matches the end (direction >= 0) or start (direction < 0) of self @@ -1207,11 +1263,11 @@ class DN(object): self_len = len(self) - start, end = self._adjust_indices(start, end, self_len) + start, end = _adjust_indices(start, end, self_len) if direction < 0: # starswith if start+pat_len > self_len: - return 0; + return 0 else: # endswith if end-start < pat_len or start > self_len: return 0 @@ -1222,7 +1278,7 @@ class DN(object): if isinstance(pattern, DN): if end-start >= pat_len: return not self._cmp_sequence(pattern, start, pat_len) - return 0; + return 0 else: return self.rdns[start] == pattern diff --git a/tests/test_ipalib/test_dn.py b/tests/test_ipalib/test_dn.py index 029297f69..c647460ab 100644 --- a/tests/test_ipalib/test_dn.py +++ b/tests/test_ipalib/test_dn.py @@ -37,7 +37,7 @@ def make_rdn_args(low, high, kind, attr=None, value=None): elif kind == 'list': result.append([new_attr, new_value]) elif kind == 'RDN': - result.append(RDN(new_attr, new_value)) + result.append(RDN((new_attr, new_value))) else: raise ValueError("Unknown kind = %s" % kind) @@ -162,6 +162,28 @@ class TestAVA(unittest.TestCase): result = cmp(ava1, self.ava1) self.assertEqual(result, 0) + # Upper case attr should still be equal + ava1 = AVA(self.attr1.upper(), self.value1) + + self.assertFalse(ava1.attr == self.attr1) + self.assertTrue(ava1.value == self.value1) + self.assertTrue(ava1 == self.ava1) + self.assertFalse(ava1 != self.ava1) + + result = cmp(ava1, self.ava1) + self.assertEqual(result, 0) + + # Upper case value should still be equal + ava1 = AVA(self.attr1, self.value1.upper()) + + self.assertTrue(ava1.attr == self.attr1) + self.assertFalse(ava1.value == self.value1) + self.assertTrue(ava1 == self.ava1) + self.assertFalse(ava1 != self.ava1) + + result = cmp(ava1, self.ava1) + self.assertEqual(result, 0) + # Make ava1's attr greater ava1.attr = self.attr1 + "1" @@ -199,7 +221,7 @@ class TestRDN(unittest.TestCase): self.ava1 = AVA(self.attr1, self.value1) self.str_rdn1 = '%s=%s' % (self.attr1, self.value1) - self.rdn1 = RDN(self.attr1, self.value1) + self.rdn1 = RDN((self.attr1, self.value1)) self.attr2 = 'ou' self.value2 = 'people' @@ -207,7 +229,7 @@ class TestRDN(unittest.TestCase): self.ava2 = AVA(self.attr2, self.value2) self.str_rdn2 = '%s=%s' % (self.attr2, self.value2) - self.rdn2 = RDN(self.attr2, self.value2) + self.rdn2 = RDN((self.attr2, self.value2)) self.str_ava3 = '%s=%s+%s=%s' % (self.attr1, self.value1, self.attr2, self.value2) @@ -216,13 +238,6 @@ class TestRDN(unittest.TestCase): def test_create(self): # Create with single attr,value pair - rdn1 = RDN(self.attr1, self.value1) - self.assertEqual(len(rdn1), 1) - self.assertEqual(rdn1, self.rdn1) - self.assertIsInstance(rdn1[0], AVA) - self.assertEqual(rdn1[0], self.ava1) - - # Create with single attr,value pair passed as a tuple rdn1 = RDN((self.attr1, self.value1)) self.assertEqual(len(rdn1), 1) self.assertEqual(rdn1, self.rdn1) @@ -230,7 +245,7 @@ class TestRDN(unittest.TestCase): self.assertEqual(rdn1[0], self.ava1) # Create with multiple attr,value pairs - rdn3 = RDN(self.attr1, self.value1, self.attr2, self.value2) + rdn3 = RDN((self.attr1, self.value1), (self.attr2, self.value2)) self.assertEqual(len(rdn3), 2) self.assertEqual(rdn3, self.rdn3) self.assertIsInstance(rdn3[0], AVA) @@ -250,7 +265,7 @@ class TestRDN(unittest.TestCase): # Create with multiple attr,value pairs but reverse # constructor parameter ordering. RDN canonical ordering # should remain the same - rdn3 = RDN(self.attr2, self.value2, self.attr1, self.value1) + rdn3 = RDN((self.attr2, self.value2), (self.attr1, self.value1)) self.assertEqual(len(rdn3), 2) self.assertEqual(rdn3, self.rdn3) self.assertIsInstance(rdn3[0], AVA) @@ -333,7 +348,7 @@ class TestRDN(unittest.TestCase): def test_cmp(self): # Equality - rdn1 = RDN(self.attr1, self.value1) + rdn1 = RDN((self.attr1, self.value1)) self.assertTrue(rdn1 == self.rdn1) self.assertFalse(rdn1 != self.rdn1) @@ -404,50 +419,50 @@ class TestRDN(unittest.TestCase): self.assertEqual(self.rdn3[:], [self.ava1, self.ava2]) def test_assignments(self): - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) rdn[0] = self.ava2 self.assertEqual(rdn, self.rdn2) - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) rdn[0] = (self.attr2, self.value2) self.assertEqual(rdn, self.rdn2) - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) rdn[self.attr1] = self.str_ava2 self.assertEqual(rdn[0], self.ava2) # Can't assign multiples to single entry - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) with self.assertRaises(TypeError): rdn[self.attr1] = self.str_ava3 - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) with self.assertRaises(TypeError): rdn[self.attr1] = (self.attr1, self.value1, self.attr2, self.value2) - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) with self.assertRaises(TypeError): rdn[self.attr1] = [(self.attr1, self.value1), (self.attr2, self.value2)] # Slices - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) self.assertEqual(rdn, self.rdn1) rdn[0:1] = [self.ava2] self.assertEqual(rdn, self.rdn2) - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) self.assertEqual(rdn, self.rdn1) rdn[:] = [(self.attr2, self.value2)] self.assertEqual(rdn, self.rdn2) - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) self.assertEqual(rdn, self.rdn1) rdn[:] = [(self.attr1, self.value1),(self.attr2, self.value2)] self.assertEqual(rdn, self.rdn3) - rdn = RDN(self.attr1, self.value1) + rdn = RDN((self.attr1, self.value1)) self.assertEqual(rdn, self.rdn1) - rdn[0:1] = [self.attr1, self.value1, self.attr2, self.value2] + rdn[0:1] = [(self.attr1, self.value1), (self.attr2, self.value2)] self.assertEqual(rdn, self.rdn3) @@ -480,23 +495,23 @@ class TestRDN(unittest.TestCase): def test_concat(self): - rdn1 = RDN(self.attr1, self.value1) - rdn2 = RDN(self.attr2, self.value2) + rdn1 = RDN((self.attr1, self.value1)) + rdn2 = RDN((self.attr2, self.value2)) # in-place addtion rdn1 += rdn2 self.assertEqual(rdn1, self.rdn3) - rdn1 = RDN(self.attr1, self.value1) + rdn1 = RDN((self.attr1, self.value1)) rdn1 += self.ava2 self.assertEqual(rdn1, self.rdn3) - rdn1 = RDN(self.attr1, self.value1) + rdn1 = RDN((self.attr1, self.value1)) rdn1 += self.str_ava2 self.assertEqual(rdn1, self.rdn3) # concatenation - rdn1 = RDN(self.attr1, self.value1) + rdn1 = RDN((self.attr1, self.value1)) rdn3 = rdn1 + rdn2 self.assertEqual(rdn3, self.rdn3) @@ -516,7 +531,7 @@ class TestDN(unittest.TestCase): self.ava1 = AVA(self.attr1, self.value1) self.str_rdn1 = '%s=%s' % (self.attr1, self.value1) - self.rdn1 = RDN(self.attr1, self.value1) + self.rdn1 = RDN((self.attr1, self.value1)) self.attr2 = 'ou' self.value2 = 'people' @@ -524,7 +539,7 @@ class TestDN(unittest.TestCase): self.ava2 = AVA(self.attr2, self.value2) self.str_rdn2 = '%s=%s' % (self.attr2, self.value2) - self.rdn2 = RDN(self.attr2, self.value2) + self.rdn2 = RDN((self.attr2, self.value2)) self.str_dn1 = self.str_rdn1 self.dn1 = DN(self.rdn1) @@ -535,12 +550,12 @@ class TestDN(unittest.TestCase): self.str_dn3 = '%s,%s' % (self.str_rdn1, self.str_rdn2) self.dn3 = DN(self.rdn1, self.rdn2) - self.base_rdn1 = RDN('dc', 'redhat') - self.base_rdn2 = RDN('dc', 'com') + self.base_rdn1 = RDN(('dc', 'redhat')) + self.base_rdn2 = RDN(('dc', 'com')) self.base_dn = DN(self.base_rdn1, self.base_rdn2) - self.container_rdn1 = RDN('cn', 'sudorules') - self.container_rdn2 = RDN('cn', 'sudo') + self.container_rdn1 = RDN(('cn', 'sudorules')) + self.container_rdn2 = RDN(('cn', 'sudo')) self.container_dn = DN(self.container_rdn1, self.container_rdn2) self.base_container_dn = DN((self.attr1, self.value1), @@ -581,7 +596,7 @@ class TestDN(unittest.TestCase): self.assertEqual(dn1[1], self.rdn2) # Create with multiple attr,value pairs passed as tuple and RDN - dn1 = DN((self.attr1, self.value1), RDN(self.attr2, self.value2)) + dn1 = DN((self.attr1, self.value1), RDN((self.attr2, self.value2))) self.assertEqual(len(dn1), 2) self.assertIsInstance(dn1[0], RDN) self.assertIsInstance(dn1[0].attr, unicode) @@ -809,7 +824,7 @@ class TestDN(unittest.TestCase): value = alt_rdn_value_arg(i) dn1[i] = attr, value dn2[orig_attr] = (attr, value) - dn3[i] = RDN(attr, value) + dn3[i] = RDN((attr, value)) self.assertEqual(dn1, dn2) self.assertEqual(dn1, dn3) |