Skip to content

Commit

Permalink
Merge pull request #103 – Use custom ldap.LDAPBytesWarning class
Browse files Browse the repository at this point in the history
  • Loading branch information
Petr Viktorin authored and GitHub committed Dec 7, 2017
2 parents a28d2be + 8290270 commit 31abc2e
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 4 deletions.
21 changes: 21 additions & 0 deletions Doc/bytes_mode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ Unspecified: relaxed mode with warnings
Text values supplied to python-ldap should be ``unicode``;
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 <filter-bytes-warning>` if needed.

Backwards-compatible behavior is not scheduled for removal until Python 2
itself reaches end of life.

Expand Down Expand Up @@ -103,3 +107,20 @@ Note that only the result's *values* are of the ``bytes`` type:
'sn': [b'Barrois'],
}),
]
.. _filter-bytes-warning:

Filtering warnings
------------------

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)
12 changes: 12 additions & 0 deletions Doc/reference/ldap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
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 31abc2e

Please sign in to comment.