From 4389d9b1787bada7de9ebabc27fbcdc2dd4701df Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 5 Dec 2017 14:53:43 +0100 Subject: [PATCH 1/2] Use custom ldap.LDAPBytesWarning class 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 --- Doc/bytes_mode.rst | 19 ++++++++++++++++++- Lib/ldap/__init__.py | 2 +- Lib/ldap/ldapobject.py | 11 +++++++++-- Tests/t_ldapobject.py | 37 ++++++++++++++++++++++++++++++++++++- 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/Doc/bytes_mode.rst b/Doc/bytes_mode.rst index b18c0ae..62ab496 100644 --- a/Doc/bytes_mode.rst +++ b/Doc/bytes_mode.rst @@ -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. @@ -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) diff --git a/Lib/ldap/__init__.py b/Lib/ldap/__init__.py index 7cb16b0..3a86095 100644 --- a/Lib/ldap/__init__.py +++ b/Lib/ldap/__init__.py @@ -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 diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index c5e62bd..f37ef24 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -14,6 +14,7 @@ 'LDAPObject', 'SimpleLDAPObject', 'ReconnectLDAPObject', + 'LDAPBytesWarning' ] @@ -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 @@ -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 @@ -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') diff --git a/Tests/t_ldapobject.py b/Tests/t_ldapobject.py index 9b6a090..835512b 100644 --- a/Tests/t_ldapobject.py +++ b/Tests/t_ldapobject.py @@ -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 @@ -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): """ From 829027081d8cb1891732b8d7d631bfcc827fe213 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 5 Dec 2017 16:07:08 +0100 Subject: [PATCH 2/2] Doc: LDAPBytesWarning doc improvements - Make filtering note apply to both causes of the warning - Add formal class documentation - Add cross-references --- Doc/bytes_mode.rst | 14 +++++++++----- Doc/reference/ldap.rst | 12 ++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Doc/bytes_mode.rst b/Doc/bytes_mode.rst index 62ab496..c775b27 100644 --- a/Doc/bytes_mode.rst +++ b/Doc/bytes_mode.rst @@ -66,9 +66,11 @@ Unspecified: relaxed mode with warnings Text values returned from python-ldap are always ``unicode``. Text values supplied to python-ldap should be ``unicode``; - warnings of type :class:`ldap.LDAPBytesWarning` are emitted when they - are not. :class:`ldap.LDAPBytesWarning` is a subclass of - :class:`BytesWarning`. + warnings are emitted when they are not. + + The warnings are of type :class:`~ldap.LDAPBytesWarning`, which + is a subclass of :class:`BytesWarning` designed to be easily + :ref:`filtered out ` if needed. Backwards-compatible behavior is not scheduled for removal until Python 2 itself reaches end of life. @@ -107,8 +109,10 @@ Note that only the result's *values* are of the ``bytes`` type: ] -Filter warning --------------- +.. _filter-bytes-warning: + +Filtering warnings +------------------ The bytes mode warnings can be filtered out and ignored with a simple filter. diff --git a/Doc/reference/ldap.rst b/Doc/reference/ldap.rst index 1f7ae5b..4b163da 100644 --- a/Doc/reference/ldap.rst +++ b/Doc/reference/ldap.rst @@ -564,6 +564,18 @@ The above exceptions are raised when a result code from an underlying API call does not indicate success. +Warnings +======== + +.. py:class:: LDAPBytesWarning + + Raised when bytes/text mismatch in non-strict bytes mode. + + See :ref:`bytes_mode` for details. + + .. versionadded:: 3.0.0 + + .. _ldap-objects: LDAPObject classes