diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index 8171b85..c550eaa 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -88,6 +88,9 @@ class SimpleLDAPObject: # Bytes mode # ---------- + + # By default, raise a TypeError when receiving invalid args + self.bytes_mode_hardfail = True if bytes_mode is None and PY2: warnings.warn( "Under Python 2, python-ldap uses bytes by default. " @@ -97,6 +100,8 @@ class SimpleLDAPObject: stacklevel=2, ) bytes_mode = True + # Disable hard failure when running in backwards compatibility mode. + self.bytes_mode_hardfail = False elif bytes_mode and not PY2: raise ValueError("bytes_mode is *not* supported under Python 3.") # On by default on Py2, off on Py3. @@ -115,7 +120,15 @@ class SimpleLDAPObject: return value elif self.bytes_mode: if not isinstance(value, bytes): - raise TypeError("All provided fields *must* be bytes when bytes mode is on; got %r" % (value,)) + if self.bytes_mode_hardfail: + raise TypeError("All provided fields *must* be bytes when bytes mode is on; got %r" % (value,)) + else: + warnings.warn( + "Received non-bytes value %r with default (disabled) bytes mode; please choose an explicit " + "option for bytes_mode on your LDAP connection" % (value,), + BytesWarning, + stacklevel=6, + ) return value.decode('utf-8') else: if not isinstance(value, text_type): diff --git a/README b/README index 8d284de..40b8dcf 100644 --- a/README +++ b/README @@ -43,7 +43,8 @@ through the ``bytes_mode`` flag to ``ldap.initialize()``. When porting from ``python-ldap``, users are advised to update their code to set ``bytes_mode=False`` on calls to these methods. Under Python 2, ``pyldap`` checks aggressively the type of provided arguments, and will raise a ``TypeError`` -for any invalid parameter. +for any invalid parameter; however, if the ``bytes_mode`` kwarg isn't provided, ``pyldap`` will only +raise warnings. The typical usage is as follow; note that only the result's *values* are of the bytes type: diff --git a/Tests/t_search.py b/Tests/t_search.py index e398287..d91a8a8 100644 --- a/Tests/t_search.py +++ b/Tests/t_search.py @@ -81,8 +81,12 @@ class TestSearch(unittest.TestCase): for value in values: self.assertEqual(type(value), bytes) - def _get_bytes_ldapobject(self): - l = LDAPObject(server.get_url(), bytes_mode=True) + def _get_bytes_ldapobject(self, explicit=True): + if explicit: + kwargs = {'bytes_mode': True} + else: + kwargs = {} + l = LDAPObject(server.get_url(), **kwargs) l.protocol_version = 3 l.set_option(ldap.OPT_REFERRALS,0) l.simple_bind_s(self.server.get_root_dn().encode('utf-8'), @@ -115,6 +119,15 @@ class TestSearch(unittest.TestCase): for value in values: self.assertEqual(type(value), bytes) + @unittest.skipUnless(PY2, "no bytes_mode under Py3") + def test_unset_bytesmode_search_warns_bytes(self): + l = self._get_bytes_ldapobject(explicit=False) + base = self.server.get_dn_suffix() + + l.search_s(base.encode('utf-8'), ldap.SCOPE_SUBTREE, '(cn=Foo*)', [b'*']) + l.search_s(base.encode('utf-8'), ldap.SCOPE_SUBTREE, b'(cn=Foo*)', ['*']) + l.search_s(base, ldap.SCOPE_SUBTREE, b'(cn=Foo*)', [b'*']) + def test_search_subtree(self): base = self.server.get_dn_suffix() l = self.ldap