Skip to content

Commit

Permalink
Use custom ldap.LDAPBytesWarning class
Browse files Browse the repository at this point in the history
Under Python 2, python-ldap now uses custom ldap.LDAPBytesWarning
instead of BytesWarning to emit warnings in default bytes mode.

Closes: https://github.com/python-ldap/python-ldap/issues/99
Signed-off-by: Christian Heimes <cheimes@redhat.com>
  • Loading branch information
Christian Heimes committed Dec 7, 2017
1 parent 084ffe0 commit 4389d9b
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 5 deletions.
19 changes: 18 additions & 1 deletion Doc/bytes_mode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ Unspecified: relaxed mode with warnings

Text values returned from python-ldap are always ``unicode``.
Text values supplied to python-ldap should be ``unicode``;
warnings are emitted when they are not.
warnings of type :class:`ldap.LDAPBytesWarning` are emitted when they
are not. :class:`ldap.LDAPBytesWarning` is a subclass of
:class:`BytesWarning`.

Backwards-compatible behavior is not scheduled for removal until Python 2
itself reaches end of life.
Expand Down Expand Up @@ -103,3 +105,18 @@ Note that only the result's *values* are of the ``bytes`` type:
'sn': [b'Barrois'],
}),
]
Filter warning
--------------

The bytes mode warnings can be filtered out and ignored with a
simple filter.

.. code-block:: python
import warnings
import ldap
if hasattr(ldap, 'LDAPBytesWarning'):
warnings.simplefilter('ignore', ldap.LDAPBytesWarning)
2 changes: 1 addition & 1 deletion Lib/ldap/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def release(self):

from ldap.functions import open,initialize,init,get_option,set_option,escape_str,strf_secs,strp_secs

from ldap.ldapobject import NO_UNIQUE_ENTRY
from ldap.ldapobject import NO_UNIQUE_ENTRY, LDAPBytesWarning

from ldap.dn import explode_dn,explode_rdn,str2dn,dn2str
del str2dn
Expand Down
11 changes: 9 additions & 2 deletions Lib/ldap/ldapobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'LDAPObject',
'SimpleLDAPObject',
'ReconnectLDAPObject',
'LDAPBytesWarning'
]


Expand All @@ -37,6 +38,12 @@
else:
text_type = str


class LDAPBytesWarning(BytesWarning):
"""python-ldap bytes mode warning
"""


class NO_UNIQUE_ENTRY(ldap.NO_SUCH_OBJECT):
"""
Exception raised if a LDAP search returned more than entry entry
Expand Down Expand Up @@ -84,7 +91,7 @@ def __init__(
"Under Python 2, python-ldap uses bytes by default. "
"This will be removed in Python 3 (no bytes for DN/RDN/field names). "
"Please call initialize(..., bytes_mode=False) explicitly.",
BytesWarning,
LDAPBytesWarning,
stacklevel=2,
)
bytes_mode = True
Expand Down Expand Up @@ -122,7 +129,7 @@ def _bytesify_input(self, value):
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,
LDAPBytesWarning,
stacklevel=6,
)
return value.encode('utf-8')
Expand Down
37 changes: 36 additions & 1 deletion Tests/t_ldapobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import os
import unittest
import pickle
import warnings
from slapdtest import SlapdTestCase, requires_sasl

# Switch off processing .ldaprc or ldap.conf before importing _ldap
Expand Down Expand Up @@ -314,7 +315,41 @@ def test007_timeout(self):
l.abandon(m)
with self.assertRaises(ldap.TIMEOUT):
result = l.result(m, timeout=0.001)


def assertIsSubclass(self, cls, other):
self.assertTrue(
issubclass(cls, other),
cls.__mro__
)

@unittest.skipUnless(PY2, "no bytes_mode under Py3")
def test_ldapbyteswarning(self):
self.assertIsSubclass(ldap.LDAPBytesWarning, BytesWarning)
self.assertIsSubclass(ldap.LDAPBytesWarning, Warning)
self.assertIsInstance(self.server.suffix, text_type)
with warnings.catch_warnings(record=True) as w:
warnings.resetwarnings()
warnings.simplefilter('default')
conn = self._get_bytes_ldapobject(explicit=False)
result = conn.search_s(
self.server.suffix,
ldap.SCOPE_SUBTREE,
b'(cn=Foo*)',
attrlist=[b'*'],
)
self.assertEqual(len(result), 4)

# ReconnectLDAP only emits one warning
self.assertGreaterEqual(len(w), 1, w)
msg = w[-1]
self.assertIs(msg.category, ldap.LDAPBytesWarning)
self.assertEqual(
text_type(msg.message),
"Received non-bytes value u'%s' with default (disabled) bytes "
"mode; please choose an explicit option for bytes_mode on your "
"LDAP connection" % self.server.suffix
)


class Test01_ReconnectLDAPObject(Test00_SimpleLDAPObject):
"""
Expand Down

0 comments on commit 4389d9b

Please sign in to comment.