Skip to content

Commit 1b2b143

Browse files
committed
Remove Python 2 support
python-ldap 3.4 will require Python 3.6 or newer. Signed-off-by: Christian Heimes <cheimes@redhat.com>
1 parent e885b62 commit 1b2b143

27 files changed

+99
-936
lines changed

.travis.yml

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,14 @@ addons:
1414
# Note: when updating Python versions, also change setup.py and tox.ini
1515
matrix:
1616
include:
17-
- python: 2.7
18-
env:
19-
- TOXENV=py27
20-
- WITH_GCOV=1
21-
- python: 3.4
22-
env:
23-
- TOXENV=py34
24-
- WITH_GCOV=1
25-
- python: 3.5
26-
env:
27-
- TOXENV=py35
28-
- WITH_GCOV=1
2917
- python: 3.6
3018
env:
3119
- TOXENV=py36
3220
- WITH_GCOV=1
33-
- python: pypy
21+
- python: pypy3
3422
env:
35-
- TOXENV=pypy
23+
- TOXENV=pypy3
24+
- CFLAGS_std="-std=c99"
3625
- python: 3.7
3726
env:
3827
- TOXENV=py37
@@ -53,10 +42,6 @@ matrix:
5342
- WITH_GCOV=1
5443
dist: xenial
5544
sudo: true
56-
- python: 2.7
57-
env:
58-
- TOXENV=py2-nosasltls
59-
- WITH_GCOV=1
6045
- python: 3.6
6146
env:
6247
- TOXENV=py3-nosasltls
@@ -68,7 +53,7 @@ matrix:
6853
env: TOXENV=doc
6954
allow_failures:
7055
- env:
71-
- TOXENV=pypy
56+
- TOXENV=pypy3
7257

7358
env:
7459
global:
@@ -87,4 +72,3 @@ install:
8772
- pip install tox-travis tox codecov
8873

8974
script: CFLAGS="$CFLAGS_warnings $CFLAGS_std" tox
90-

Doc/bytes_mode.rst

Lines changed: 1 addition & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ What's text, and what's bytes
2727

2828
The LDAP protocol states that some fields (distinguished names, relative
2929
distinguished names, attribute names, queries) be encoded in UTF-8.
30-
In python-ldap, these are represented as text (``str`` on Python 3,
31-
``unicode`` on Python 2).
30+
In python-ldap, these are represented as text (``str`` on Python 3).
3231

3332
Attribute *values*, on the other hand, **MAY**
3433
contain any type of data, including text.
@@ -44,96 +43,3 @@ The bytes mode
4443
--------------
4544

4645
In Python 3, text values are represented as ``str``, the Unicode text type.
47-
48-
In Python 2, the behavior of python-ldap 3.0 is influenced by a ``bytes_mode``
49-
argument to :func:`ldap.initialize`:
50-
51-
``bytes_mode=True`` (backwards compatible):
52-
Text values are represented as bytes (``str``) encoded using UTF-8.
53-
54-
``bytes_mode=False`` (future compatible):
55-
Text values are represented as ``unicode``.
56-
57-
If not given explicitly, python-ldap will default to ``bytes_mode=True``,
58-
but if a ``unicode`` value is supplied to it, it will warn and use that value.
59-
60-
Backwards-compatible behavior is not scheduled for removal until Python 2
61-
itself reaches end of life.
62-
63-
64-
Errors, warnings, and automatic encoding
65-
----------------------------------------
66-
67-
While the type of values *returned* from python-ldap is always given by
68-
``bytes_mode``, for Python 2 the behavior for “wrong-type” values *passed in*
69-
can be controlled by the ``bytes_strictness`` argument to
70-
:func:`ldap.initialize`:
71-
72-
``bytes_strictness='error'`` (default if ``bytes_mode`` is specified):
73-
A ``TypeError`` is raised.
74-
75-
``bytes_strictness='warn'`` (default when ``bytes_mode`` is not given explicitly):
76-
A warning is raised, and the value is encoded/decoded
77-
using the UTF-8 encoding.
78-
79-
The warnings are of type :class:`~ldap.LDAPBytesWarning`, which
80-
is a subclass of :class:`BytesWarning` designed to be easily
81-
:ref:`filtered out <filter-bytes-warning>` if needed.
82-
83-
``bytes_strictness='silent'``:
84-
The value is automatically encoded/decoded using the UTF-8 encoding.
85-
86-
On Python 3, ``bytes_strictness`` is ignored and a ``TypeError`` is always
87-
raised.
88-
89-
When setting ``bytes_strictness``, an explicit value for ``bytes_mode`` needs
90-
to be given as well.
91-
92-
93-
Porting recommendations
94-
-----------------------
95-
96-
Since end of life of Python 2 is coming in a few years, projects are strongly
97-
urged to make their code compatible with Python 3. General instructions for
98-
this are provided :ref:`in Python documentation <pyporting-howto>` and in the
99-
`Conservative porting guide`_.
100-
101-
.. _Conservative porting guide: https://portingguide.readthedocs.io/en/latest/
102-
103-
104-
When porting from python-ldap 2.x, users are advised to update their code
105-
to set ``bytes_mode=False``, and fix any resulting failures.
106-
107-
The typical usage is as follows.
108-
Note that only the result's *values* are of the ``bytes`` type:
109-
110-
.. code-block:: pycon
111-
112-
>>> import ldap
113-
>>> con = ldap.initialize('ldap://localhost:389', bytes_mode=False)
114-
>>> con.simple_bind_s(u'login', u'secret_password')
115-
>>> results = con.search_s(u'ou=people,dc=example,dc=org', ldap.SCOPE_SUBTREE, u"(cn=Raphaël)")
116-
>>> results
117-
[
118-
("cn=Raphaël,ou=people,dc=example,dc=org", {
119-
'cn': [b'Rapha\xc3\xabl'],
120-
'sn': [b'Barrois'],
121-
}),
122-
]
123-
124-
125-
.. _filter-bytes-warning:
126-
127-
Filtering warnings
128-
------------------
129-
130-
The bytes mode warnings can be filtered out and ignored with a
131-
simple filter.
132-
133-
.. code-block:: python
134-
135-
import warnings
136-
import ldap
137-
138-
if hasattr(ldap, 'LDAPBytesWarning'):
139-
warnings.simplefilter('ignore', ldap.LDAPBytesWarning)

Doc/faq.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Usage
2929
.. _pyldap: https://pypi.org/project/pyldap/
3030

3131

32-
**Q**: Does it work with Python 2.6? (1.5|2.0|2.1|2.2|2.3|2.4|2.5)?
32+
**Q**: Does it work with Python 2.7? (1.5|2.0|2.1|2.2|2.3|2.4|2.5|2.6|2.7)?
3333

3434
**A**: No. Old versions of python-ldap are still available from PyPI, though.
3535

Doc/reference/ldap.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,8 @@ This module defines the following functions:
6363
*trace_file* specifies a file-like object as target of the debug log and
6464
*trace_stack_limit* specifies the stack limit of tracebacks in debug log.
6565

66-
The *bytes_mode* and *bytes_strictness* arguments specify text/bytes
67-
behavior under Python 2.
68-
See :ref:`text-bytes` for a complete documentation.
66+
The *bytes_mode* and *bytes_strictness* arguments are deprecated and
67+
ignored.
6968

7069
Possible values for *trace_level* are
7170
:py:const:`0` for no logging,
@@ -86,6 +85,10 @@ This module defines the following functions:
8685

8786
The *fileno* argument was added.
8887

88+
.. deprecated:: 3.4
89+
90+
*bytes_mode* and *bytes_strictness* arguments are deprecated.
91+
8992

9093
.. py:function:: get_option(option) -> int|string
9194

Doc/reference/ldapurl.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99

1010
This module parses and generates LDAP URLs. It is implemented in pure Python
1111
and does not rely on any non-standard modules. Therefore it can be used stand-
12-
alone without the rest of the python-ldap package. Compatibility note: This
13-
module has been solely tested on Python 2.x and above.
12+
alone without the rest of the python-ldap package.
1413

1514
.. seealso::
1615

Doc/sample_workflow.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ python-ldap won't affect the rest of your system::
3131

3232
$ python3 -m venv __venv__
3333

34-
(For Python 2, install `virtualenv`_ and use it instead of ``python3 -m venv``.)
35-
3634
.. _git: https://git-scm.com/
3735
.. _virtualenv: https://virtualenv.pypa.io/en/stable/
3836

Lib/ldap/cidict.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"""
88
import warnings
99

10-
from ldap.compat import MutableMapping
10+
from collections.abc import MutableMapping
1111
from ldap import __version__
1212

1313

Lib/ldap/compat.py

Lines changed: 22 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,23 @@
11
"""Compatibility wrappers for Py2/Py3."""
2-
3-
import sys
4-
import os
5-
6-
if sys.version_info[0] < 3:
7-
from UserDict import UserDict, IterableUserDict
8-
from urllib import quote
9-
from urllib import quote_plus
10-
from urllib import unquote as urllib_unquote
11-
from urllib import urlopen
12-
from urlparse import urlparse
13-
from collections import MutableMapping
14-
15-
def unquote(uri):
16-
"""Specialized unquote that uses UTF-8 for parsing."""
17-
uri = uri.encode('ascii')
18-
unquoted = urllib_unquote(uri)
19-
return unquoted.decode('utf-8')
20-
21-
# Old-style of re-raising an exception is SyntaxError in Python 3,
22-
# so hide behind exec() so the Python 3 parser doesn't see it
23-
exec('''def reraise(exc_type, exc_value, exc_traceback):
24-
"""Re-raise an exception given information from sys.exc_info()
25-
26-
Note that unlike six.reraise, this does not support replacing the
27-
traceback. All arguments must come from a single sys.exc_info() call.
28-
"""
29-
raise exc_type, exc_value, exc_traceback
30-
''')
31-
32-
else:
33-
from collections import UserDict
34-
IterableUserDict = UserDict
35-
from urllib.parse import quote, quote_plus, unquote, urlparse
36-
from urllib.request import urlopen
37-
from collections.abc import MutableMapping
38-
39-
def reraise(exc_type, exc_value, exc_traceback):
40-
"""Re-raise an exception given information from sys.exc_info()
41-
42-
Note that unlike six.reraise, this does not support replacing the
43-
traceback. All arguments must come from a single sys.exc_info() call.
44-
"""
45-
# In Python 3, all exception info is contained in one object.
46-
raise exc_value
47-
48-
try:
49-
from shutil import which
50-
except ImportError:
51-
# shutil.which() from Python 3.6
52-
# "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
53-
# 2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software Foundation;
54-
# All Rights Reserved"
55-
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
56-
"""Given a command, mode, and a PATH string, return the path which
57-
conforms to the given mode on the PATH, or None if there is no such
58-
file.
59-
60-
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
61-
of os.environ.get("PATH"), or can be overridden with a custom search
62-
path.
63-
64-
"""
65-
# Check that a given file can be accessed with the correct mode.
66-
# Additionally check that `file` is not a directory, as on Windows
67-
# directories pass the os.access check.
68-
def _access_check(fn, mode):
69-
return (os.path.exists(fn) and os.access(fn, mode)
70-
and not os.path.isdir(fn))
71-
72-
# If we're given a path with a directory part, look it up directly rather
73-
# than referring to PATH directories. This includes checking relative to the
74-
# current directory, e.g. ./script
75-
if os.path.dirname(cmd):
76-
if _access_check(cmd, mode):
77-
return cmd
78-
return None
79-
80-
if path is None:
81-
path = os.environ.get("PATH", os.defpath)
82-
if not path:
83-
return None
84-
path = path.split(os.pathsep)
85-
86-
if sys.platform == "win32":
87-
# The current directory takes precedence on Windows.
88-
if not os.curdir in path:
89-
path.insert(0, os.curdir)
90-
91-
# PATHEXT is necessary to check on Windows.
92-
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
93-
# See if the given file matches any of the expected path extensions.
94-
# This will allow us to short circuit when given "python.exe".
95-
# If it does match, only test that one, otherwise we have to try
96-
# others.
97-
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
98-
files = [cmd]
99-
else:
100-
files = [cmd + ext for ext in pathext]
101-
else:
102-
# On other platforms you don't have things like PATHEXT to tell you
103-
# what file suffixes are executable, so just pass on cmd as-is.
104-
files = [cmd]
105-
106-
seen = set()
107-
for dir in path:
108-
normdir = os.path.normcase(dir)
109-
if not normdir in seen:
110-
seen.add(normdir)
111-
for thefile in files:
112-
name = os.path.join(dir, thefile)
113-
if _access_check(name, mode):
114-
return name
115-
return None
2+
import warnings
3+
4+
warnings.warn(
5+
DeprecationWarning,
6+
"The ldap.compat module is deprecated and will be removed in the future"
7+
)
8+
9+
from collections import UserDict
10+
IterableUserDict = UserDict
11+
from urllib.parse import quote, quote_plus, unquote, urlparse
12+
from urllib.request import urlopen
13+
from collections.abc import MutableMapping
14+
from shutil import which
15+
16+
def reraise(exc_type, exc_value, exc_traceback):
17+
"""Re-raise an exception given information from sys.exc_info()
18+
19+
Note that unlike six.reraise, this does not support replacing the
20+
traceback. All arguments must come from a single sys.exc_info() call.
21+
"""
22+
# In Python 3, all exception info is contained in one object.
23+
raise exc_value

Lib/ldap/controls/sss.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@
2222
from pyasn1.type import univ, namedtype, tag, namedval, constraint
2323
from pyasn1.codec.ber import encoder, decoder
2424

25-
PY2 = sys.version_info[0] <= 2
26-
if not PY2:
27-
basestring = str
28-
2925

3026
# SortKeyList ::= SEQUENCE OF SEQUENCE {
3127
# attributeType AttributeDescription,
@@ -63,7 +59,7 @@ def __init__(
6359
):
6460
RequestControl.__init__(self,self.controlType,criticality)
6561
self.ordering_rules = ordering_rules
66-
if isinstance(ordering_rules, basestring):
62+
if isinstance(ordering_rules, str):
6763
ordering_rules = [ordering_rules]
6864
for rule in ordering_rules:
6965
rule = rule.split(':')

Lib/ldap/dn.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
44
See https://www.python-ldap.org/ for details.
55
"""
6-
7-
import sys
86
from ldap.pkginfo import __version__
97

108
import _ldap
@@ -47,8 +45,6 @@ def str2dn(dn,flags=0):
4745
"""
4846
if not dn:
4947
return []
50-
if sys.version_info[0] < 3 and isinstance(dn, unicode):
51-
dn = dn.encode('utf-8')
5248
return ldap.functions._ldap_function_call(None,_ldap.str2dn,dn,flags)
5349

5450

0 commit comments

Comments
 (0)