diff --git a/CHANGES b/CHANGES index df17338..a5540e5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,12 @@ +---------------------------------------------------------------- +Released 2.4.22 2015-10-xx + +Changes since 2.4.21: + +Lib/ +* LDIFParser now also accepts value-spec without a space + after the colon. + ---------------------------------------------------------------- Released 2.4.21 2015-09-25 @@ -1195,4 +1204,4 @@ Released 2.0.0pre02 2002-02-01 ---------------------------------------------------------------- Released 1.10alpha3 2000-09-19 -$Id: CHANGES,v 1.356 2015/09/25 16:21:47 stroeder Exp $ +$Id: CHANGES,v 1.358 2015/09/30 17:17:28 stroeder Exp $ diff --git a/Lib/dsml.py b/Lib/dsml.py index e7e76ae..ab886fb 100644 --- a/Lib/dsml.py +++ b/Lib/dsml.py @@ -4,13 +4,13 @@ dsml - generate and parse DSMLv1 data See http://www.python-ldap.org/ for details. -$Id: dsml.py,v 1.38 2015/08/08 13:36:30 stroeder Exp $ +$Id: dsml.py,v 1.39 2015/09/30 17:15:53 stroeder Exp $ Python compability note: Tested with Python 2.0+. """ -__version__ = '2.4.21' +__version__ = '2.4.22' import string,base64 diff --git a/Lib/ldap/__init__.py b/Lib/ldap/__init__.py index afa1ad3..8c2cd64 100644 --- a/Lib/ldap/__init__.py +++ b/Lib/ldap/__init__.py @@ -3,12 +3,12 @@ ldap - base module See http://www.python-ldap.org/ for details. -$Id: __init__.py,v 1.98 2015/08/08 13:36:30 stroeder Exp $ +$Id: __init__.py,v 1.99 2015/09/30 17:15:53 stroeder Exp $ """ # This is also the overall release version number -__version__ = '2.4.21' +__version__ = '2.4.22' import sys diff --git a/Lib/ldapurl.py b/Lib/ldapurl.py index 181684b..a2b49b5 100644 --- a/Lib/ldapurl.py +++ b/Lib/ldapurl.py @@ -3,7 +3,7 @@ ldapurl - handling of LDAP URLs as described in RFC 4516 See http://www.python-ldap.org/ for details. -\$Id: ldapurl.py,v 1.73 2015/08/08 13:36:30 stroeder Exp $ +\$Id: ldapurl.py,v 1.74 2015/09/30 17:15:53 stroeder Exp $ Python compability note: This module only works with Python 2.0+ since @@ -11,7 +11,7 @@ This module only works with Python 2.0+ since 2. list comprehensions are used. """ -__version__ = '2.4.21' +__version__ = '2.4.22' __all__ = [ # constants diff --git a/Lib/ldif.py b/Lib/ldif.py index 0d0bc6d..2622adc 100644 --- a/Lib/ldif.py +++ b/Lib/ldif.py @@ -3,13 +3,13 @@ ldif - generate and parse LDIF data (see RFC 2849) See http://www.python-ldap.org/ for details. -$Id: ldif.py,v 1.83 2015/08/08 13:36:30 stroeder Exp $ +$Id: ldif.py,v 1.85 2015/09/30 17:17:28 stroeder Exp $ Python compability note: Tested with Python 2.0+, but should work with Python 1.5.2+. """ -__version__ = '2.4.21' +__version__ = '2.4.22' __all__ = [ # constants @@ -347,7 +347,7 @@ class LDIFParser: # if needed attribute value is BASE64 decoded value_spec = unfolded_line[colon_pos:colon_pos+2] if value_spec==': ': - attr_value = unfolded_line[colon_pos+2:] + attr_value = unfolded_line[colon_pos+2:].lstrip() if isinstance(unfolded_line, unicode): attr_value = attr_value.encode('utf-8') elif value_spec=='::': @@ -364,8 +364,8 @@ class LDIFParser: u = urlparse(url) if u[0] in self._process_url_schemes: attr_value = urllib.urlopen(url).read() - elif value_spec==':\r\n' or value_spec=='\n': - attr_value = b'' + else: + attr_value = unfolded_line[colon_pos+1:].encode('utf-8') return attr_type,attr_value def parse_entry_records(self): diff --git a/Tests/t_ldif.py b/Tests/t_ldif.py index 8620b05..efd69ec 100644 --- a/Tests/t_ldif.py +++ b/Tests/t_ldif.py @@ -15,29 +15,24 @@ except ImportError: class TestParse(unittest.TestCase): maxDiff = None - def check_ldif_to_records(self, ldif_string, expected): - #import pdb; pdb.set_trace() - got = ldif.ParseLDIF(StringIO(ldif_string)) - self.assertEqual(got, expected) + def _parse_entry_records(self, ldif_string): + return ldif.ParseLDIF(StringIO(ldif_string)) - def check_records_to_ldif(self, records, expected): + def _unparse_entry_records(self, records): f = StringIO() ldif_writer = ldif.LDIFWriter(f) for dn, attrs in records: ldif_writer.unparse(dn, attrs) - got = f.getvalue() - self.assertEqual(got, expected) + return f.getvalue() - def check_roundtrip(self, ldif_source, records, ldif_expected=None): + def check_roundtrip(self, ldif_source, entry_records): ldif_source = textwrap.dedent(ldif_source).lstrip() + '\n' - if ldif_expected is None: - ldif_expected = ldif_source - else: - ldif_expected = textwrap.dedent(ldif_expected).lstrip() + '\n' - - self.check_ldif_to_records(ldif_source, records) - self.check_records_to_ldif(records, ldif_expected) - self.check_ldif_to_records(ldif_expected, records) + parsed_entry_records = self._parse_entry_records(ldif_source) + parsed_entry_records2 = self._parse_entry_records( + self._unparse_entry_records(entry_records) + ) + self.assertEqual(parsed_entry_records, entry_records) + self.assertEqual(parsed_entry_records2, entry_records) def test_simple(self): self.check_roundtrip(""" @@ -48,6 +43,15 @@ class TestParse(unittest.TestCase): ('cn=x,cn=y,cn=z', {'attrib': [b'value', b'value2']}), ]) + def test_simple2(self): + self.check_roundtrip(""" + dn:cn=x,cn=y,cn=z + attrib:value + attrib:value2 + """, [ + ('cn=x,cn=y,cn=z', {'attrib': [b'value', b'value2']}), + ]) + def test_multiple(self): self.check_roundtrip(""" dn: cn=x,cn=y,cn=z @@ -74,12 +78,7 @@ class TestParse(unittest.TestCase): """ % ('asdf.' * 20), [ ('cn=x,cn=y,cn=z', {'attrib': [b'verylong value'], 'attrib2': [b'asdf.' * 20]}), - ], """ - dn: cn=x,cn=y,cn=z - attrib: verylong value - attrib2: asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.as - df.asdf.asdf.asdf.asdf.asdf.asdf. - """) + ]) def test_empty(self): self.check_roundtrip(""" @@ -98,6 +97,14 @@ class TestParse(unittest.TestCase): ('cn=x,cn=y,cn=z', {'attrib': [b'\t\0\n:%@']}), ]) + def test_binary2(self): + self.check_roundtrip(""" + dn: cn=x,cn=y,cn=z + attrib::CQAKOiVA + """, [ + ('cn=x,cn=y,cn=z', {'attrib': [b'\t\0\n:%@']}), + ]) + def test_unicode(self): self.check_roundtrip(""" dn: cn=Michael Stroeder,dc=stroeder,dc=com @@ -105,10 +112,7 @@ class TestParse(unittest.TestCase): """, [ ('cn=Michael Stroeder,dc=stroeder,dc=com', {'lastname': [b'Str\303\266der']}), - ], """ - dn: cn=Michael Stroeder,dc=stroeder,dc=com - lastname:: U3Ryw7ZkZXI= - """) + ]) def test_sorted(self): self.check_roundtrip(""" @@ -120,12 +124,7 @@ class TestParse(unittest.TestCase): ('cn=x,cn=y,cn=z', {'a': [b'value_a'], 'b': [b'value_b'], 'c': [b'value_c']}), - ], """ - dn: cn=x,cn=y,cn=z - a: value_a - b: value_b - c: value_c - """) + ]) if __name__ == '__main__':