From fc3faa3907e2db5fa709f317df9ed4d6d1313441 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Fri, 4 Sep 2015 15:50:36 -0400
Subject: [PATCH] Ticket 48204 - update lib389 for python3

Description:  Updated lib389 for python3

https://fedorahosted.org/389/ticket/48204

Reviewed by: ?
---
 lib389/__init__.py                  |  61 ++++++++--------
 lib389/_constants.py                |   4 +-
 lib389/_entry.py                    |  56 +++++++--------
 lib389/_ldifconn.py                 |   6 +-
 lib389/_replication.py              |  23 ++++---
 lib389/agreement.py                 |   5 +-
 lib389/backend.py                   | 134 ++++++++++++++++++------------------
 lib389/changelog.py                 |   2 +-
 lib389/ds_instance.py               |  24 ++++---
 lib389/index.py                     |  21 +++---
 lib389/mappingTree.py               | 118 +++++++++++++++----------------
 lib389/replica.py                   |  22 +++---
 lib389/schema.py                    |  32 +++++----
 lib389/tools.py                     |  56 ++++++++-------
 tests/config.py                     |   3 +-
 tests/config_test.py                |  26 +++----
 tests/dsadmin_basic_test.py         |  12 ++--
 tests/dsadmin_create_remove_test.py |  20 +++---
 tests/dsadmin_test.py               |  22 +++---
 tests/entry_test.py                 |   2 +-
 tests/mappingTree_test.py           |  83 +++++++++++-----------
 21 files changed, 376 insertions(+), 356 deletions(-)

diff --git a/lib389/__init__.py b/lib389/__init__.py
index 281f48f..e655a2e 100644
--- a/lib389/__init__.py
+++ b/lib389/__init__.py
@@ -17,6 +17,7 @@ except ImportError:
     import popen2
     HASPOPEN = False
 
+import io
 import sys
 import os
 import stat
@@ -24,13 +25,13 @@ import pwd
 import grp
 import os.path
 import base64
-import urllib
-import urllib2
+import six.moves.urllib.request
+import six.moves.urllib.parse
+import six.moves.urllib.error
 import socket
 import ldif
 import re
 import ldap
-import cStringIO
 import time
 import operator
 import shutil
@@ -40,6 +41,8 @@ import decimal
 import glob
 import tarfile
 import subprocess
+import collections
+import six
 
 from ldap.ldapobject import SimpleLDAPObject
 from ldapurl import LDAPUrl
@@ -47,8 +50,6 @@ from ldap.cidict import cidict
 from ldap import LDAPError
 # file in this package
 
-
-
 from lib389._constants import *
 from lib389._entry import Entry
 from lib389._replication import CSN, RUV
@@ -182,7 +183,7 @@ class DirSrv(SimpleLDAPObject):
             if cnconfig:
                 return cnconfig.getValue(attrname)
             return None
-        except IOError, err:  # except..as.. doedn't work on python 2.4
+        except IOError as err:
             log.error("could not read dse config file")
             raise err
 
@@ -273,9 +274,9 @@ class DirSrv(SimpleLDAPObject):
                 self.dbdir = os.path.dirname(ent.getValue('nsslapd-directory'))
             except (ldap.INSUFFICIENT_ACCESS, ldap.CONNECT_ERROR, NoSuchEntryError):
                 log.exception("Skipping exception during initialization")
-            except ldap.OPERATIONS_ERROR, e:
+            except ldap.OPERATIONS_ERROR as e:
                 log.exception("Skipping exception: Probably Active Directory")
-            except ldap.LDAPError, e:
+            except ldap.LDAPError as e:
                 log.exception("Error during initialization, error: " + e.message['desc'])
                 raise
 
@@ -313,7 +314,7 @@ class DirSrv(SimpleLDAPObject):
                     self.start_tls_s()
                 try:
                     self.simple_bind_s(self.binddn, self.bindpw)
-                except ldap.SERVER_DOWN, e:
+                except ldap.SERVER_DOWN as e:
                     # TODO add server info in exception
                     log.debug("Cannot connect to %r" % uri)
                     raise e
@@ -895,7 +896,7 @@ class DirSrv(SimpleLDAPObject):
                     self.start_tls_s()
                 try:
                     self.simple_bind_s(self.binddn, self.bindpw)
-                except ldap.SERVER_DOWN, e:
+                except ldap.SERVER_DOWN as e:
                     # TODO add server info in exception
                     log.debug("Cannot connect to %r" % uri)
                     raise e
@@ -1303,7 +1304,7 @@ class DirSrv(SimpleLDAPObject):
         in an Entry class that provides some useful methods"""
         for name in dir(self.__class__.__bases__[0]):
             attr = getattr(self, name)
-            if callable(attr):
+            if isinstance(attr, collections.Callable):
                 setattr(self, name, wrapper(attr, name))
 
     def addLDIF(self, input_file, cont=False):
@@ -1312,14 +1313,14 @@ class DirSrv(SimpleLDAPObject):
                          ignored_attr_types=None, max_entries=0, process_url_schemes=None
                          ):
                 myfile = input_file
-                if isinstance(input_file, basestring):
+                if isinstance(input_file, six.string_types):
                     myfile = open(input_file, "r")
                 self.conn = conn
                 self.cont = cont
                 ldif.LDIFParser.__init__(self, myfile, ignored_attr_types,
                                          max_entries, process_url_schemes)
                 self.parse()
-                if isinstance(input_file, basestring):
+                if isinstance(input_file, six.string_types):
                     myfile.close()
 
             def handle(self, dn, entry):
@@ -1328,7 +1329,7 @@ class DirSrv(SimpleLDAPObject):
                 newentry = Entry((dn, entry))
                 try:
                     self.conn.add_s(newentry)
-                except ldap.LDAPError, e:
+                except ldap.LDAPError as e:
                     if not self.cont:
                         raise e
                     log.exception("Error: could not add entry %s" % dn)
@@ -1470,11 +1471,11 @@ class DirSrv(SimpleLDAPObject):
             for attr in dbattrs:
                 fmtstr += ' %%(%s)%ds' % (attr, cols[attr][0])
                 ret += ' %*s' % tuple(cols[attr])
-            for dbf in dbrec.itervalues():
+            for dbf in six.itervalues(dbrec):
                 ret += "\n" + (fmtstr % dbf)
             return ret
-        except Exception, e:
-            print "caught exception", str(e)
+        except Exception as e:
+            print ("caught exception", str(e))
         return ''
 
     def waitForEntry(self, dn, timeout=7200, attr='', quiet=True):
@@ -1501,8 +1502,8 @@ class DirSrv(SimpleLDAPObject):
                 pass  # found entry, but no attr
             except ldap.NO_SUCH_OBJECT:
                 pass  # no entry yet
-            except ldap.LDAPError, e:  # badness
-                print "\nError reading entry", dn, e
+            except ldap.LDAPError as e:  # badness
+                print("\nError reading entry", dn, e)
                 break
             if not entry:
                 if not quiet:
@@ -1511,12 +1512,12 @@ class DirSrv(SimpleLDAPObject):
                 time.sleep(1)
 
         if not entry and int(time.time()) > timeout:
-            print "\nwaitForEntry timeout for %s for %s" % (self, dn)
+            print("\nwaitForEntry timeout for %s for %s" % (self, dn))
         elif entry:
             if not quiet:
-                print "\nThe waited for entry is:", entry
+                print("\nThe waited for entry is:", entry)
         else:
-            print "\nError: could not read entry %s from %s" % (dn, self)
+            print("\nError: could not read entry %s from %s" % (dn, self))
 
         return entry
 
@@ -1577,7 +1578,7 @@ class DirSrv(SimpleLDAPObject):
         try:
             self.modify_s(dn, mod)
         except ldap.TYPE_OR_VALUE_EXISTS:
-            print "chainOnUpdate already enabled for %s" % suffix
+            print("chainOnUpdate already enabled for %s" % suffix)
 
     def setupConsumerChainOnUpdate(self, suffix, isIntermediate, binddn, bindpw, urls, beargs=None):
         beargs = beargs or {}
@@ -1880,7 +1881,7 @@ class DirSrv(SimpleLDAPObject):
                     if entry.hasValue('description', test_value):
                         replicated = True
                         break
-                except ldap.LDAPError, e:
+                except ldap.LDAPError as e:
                     log.fatal('testReplication() failed to modify (%s), error (%d)'
                               % (suffix, e.message['desc']))
                     return False
@@ -1995,9 +1996,9 @@ class DirSrv(SimpleLDAPObject):
             try:
                 self.add_s(ent)
                 if verbose:
-                    print "created subtree pwpolicy entry", ent.dn
+                    print("created subtree pwpolicy entry", ent.dn)
             except ldap.ALREADY_EXISTS:
-                print "subtree pwpolicy entry", ent.dn, "already exists - skipping"
+                print("subtree pwpolicy entry", ent.dn, "already exists - skipping")
         self.setPwdPolicy({'nsslapd-pwpolicy-local': 'on'})
         self.setDNPwdPolicy(poldn, pwdpolicy, **pwdargs)
 
@@ -2016,9 +2017,9 @@ class DirSrv(SimpleLDAPObject):
             try:
                 self.add_s(ent)
                 if verbose:
-                    print "created user pwpolicy entry", ent.dn
+                    print("created user pwpolicy entry", ent.dn)
             except ldap.ALREADY_EXISTS:
-                print "user pwpolicy entry", ent.dn, "already exists - skipping"
+                print("user pwpolicy entry", ent.dn, "already exists - skipping")
         mod = [(ldap.MOD_REPLACE, 'pwdpolicysubentry', poldn)]
         self.modify_s(user, mod)
         self.setPwdPolicy({'nsslapd-pwpolicy-local': 'on'})
@@ -2030,10 +2031,10 @@ class DirSrv(SimpleLDAPObject):
     def setDNPwdPolicy(self, dn, pwdpolicy, **pwdargs):
         """input is dict of attr/vals"""
         mods = []
-        for (attr, val) in pwdpolicy.iteritems():
+        for (attr, val) in six.iteritems(pwdpolicy):
             mods.append((ldap.MOD_REPLACE, attr, str(val)))
         if pwdargs:
-            for (attr, val) in pwdargs.iteritems():
+            for (attr, val) in six.iteritems(pwdargs):
                 mods.append((ldap.MOD_REPLACE, attr, str(val)))
         self.modify_s(dn, mods)
 
diff --git a/lib389/_constants.py b/lib389/_constants.py
index 79f00cb..d7e5496 100644
--- a/lib389/_constants.py
+++ b/lib389/_constants.py
@@ -7,7 +7,7 @@ from lib389.properties import *
 
 (MASTER_TYPE,
  HUB_TYPE,
- LEAF_TYPE) = range(3)
+ LEAF_TYPE) = list(range(3))
 
 REPLICAROLE_MASTER    = "master"
 REPLICAROLE_HUB       = "hub"
@@ -186,7 +186,7 @@ LOG_DEFAULT,
 LOG_CACHE,
 LOG_PLUGIN,
 LOG_MICROSECONDS,
-LOG_ACL_SUMMARY) = [1 << x for x in (range(8) + range(11, 19))]
+LOG_ACL_SUMMARY) = [1 << x for x in (list(range(8)) + list(range(11, 19)))]
 
 
 #
diff --git a/lib389/_entry.py b/lib389/_entry.py
index 2bab0f9..482ef9e 100644
--- a/lib389/_entry.py
+++ b/lib389/_entry.py
@@ -1,7 +1,7 @@
 import ldif
 import re
 from ldap.cidict import cidict
-import cStringIO
+import six
 
 import logging
 import ldap
@@ -10,12 +10,13 @@ from lib389.properties import *
 logging.basicConfig(level=logging.DEBUG)
 log = logging.getLogger(__name__)
 
+
 class FormatDict(cidict):
     def __getitem__(self, name):
         if name in self:
             return ' '.join(cidict.__getitem__(self, name))
         return None
-            
+
 
 class Entry(object):
     """This class represents an LDAP Entry object.
@@ -56,10 +57,10 @@ class Entry(object):
                 else:
                     self.dn = entrydata[0]
                     self.data = cidict(entrydata[1])
-            elif isinstance(entrydata, basestring):
+            elif isinstance(entrydata, six.string_types):
                 if not '=' in entrydata:
                     raise ValueError('Entry dn must contain "="')
-                    
+
                 self.dn = entrydata
                 self.data = cidict()
         else:
@@ -67,7 +68,7 @@ class Entry(object):
             self.dn = ''
             self.data = cidict()
 
-    def __nonzero__(self):
+    def __bool__(self):
         """This allows us to do tests like if entry: returns false if there is no data,
         true otherwise"""
         return self.data is not None and len(self.data) > 0
@@ -98,7 +99,7 @@ class Entry(object):
 
     def hasValue(self, name, val=None):
         """True if the given attribute is present and has the given value
-        
+
             TODO: list comparison preserves order: should I use a set?
         """
         if not self.hasAttr(name):
@@ -136,13 +137,13 @@ class Entry(object):
     def getAttrs(self):
         if not self.data:
             return []
-        return self.data.keys()
+        return list(self.data.keys())
 
     def iterAttrs(self, attrsOnly=False):
         if attrsOnly:
-            return self.data.iterkeys()
+            return six.iterkeys(self.data)
         else:
-            return self.data.iteritems()
+            return six.iteritems(self.data)
 
     setValues = setValue
 
@@ -150,7 +151,7 @@ class Entry(object):
         """Convert the attrs and values to a list of 2-tuples.  The first element
         of the tuple is the attribute name.  The second element is either a
         single value or a list of values."""
-        return self.data.items()
+        return list(self.data.items())
 
     def getref(self):
         return self.ref
@@ -162,7 +163,7 @@ class Entry(object):
     def update(self, dct):
         """Update passthru to the data attribute."""
         log.debug("update dn: %r with %r" % (self.dn, dct))
-        for k, v in dct.items():
+        for k, v in list(dct.items()):
             if hasattr(v, '__iter__'):
                 self.data[k] = v
             else:
@@ -170,7 +171,7 @@ class Entry(object):
 
     def __repr__(self):
         """Convert the Entry to its LDIF representation"""
-        sio = cStringIO.StringIO()
+        sio = six.StringIO()
         # what's all this then?  the unparse method will currently only accept
         # a list or a dict, not a class derived from them.  self.data is a
         # cidict, so unparse barfs on it.  I've filed a bug against python-ldap,
@@ -181,7 +182,7 @@ class Entry(object):
         ldif.LDIFWriter(
             sio, Entry.base64_attrs, 1000).unparse(self.dn, newdata)
         return sio.getvalue()
-    
+
     def create(self, type=ENTRY_TYPE_PERSON, entry_dn=None, properties=None):
         """ Return - eventually creating - a person entry with the given dn and pwd.
 
@@ -189,7 +190,7 @@ class Entry(object):
         """
         if not entry_dn:
             raise ValueError("entry_dn is mandatory")
-        
+
         if not type:
             raise ValueError("type is mandatory")
 
@@ -200,7 +201,7 @@ class Entry(object):
         ent.setValues(ENTRY_CN,           properties.get(ENTRY_CN, "bind dn pseudo user"))
         if type == ENTRY_TYPE_INETPERSON:
             ent.setValues(ENTRY_UID,      properties.get(ENTRY_UID, "bind dn pseudo user"))
-            
+
         try:
             self.add_s(ent)
         except ldap.ALREADY_EXISTS:
@@ -216,11 +217,13 @@ class Entry(object):
     def getAcis(self):
         if not self.hasAttr('aci'):
             # There should be a better way to do this? Perhaps
-            # self search for the aci attr?  
+            # self search for the aci attr?
             return []
-        self.acis = map(lambda a: EntryAci(self, a), self.getValues('aci'))
+        self.acis = [EntryAci(self, a) for a in self.getValues('aci')]
+
         return self.acis
 
+
 class EntryAci(object):
 
     # See https://access.redhat.com/documentation/en-US/Red_Hat_Directory_Server/10/html/Administration_Guide/Managing_Access_Control-Bind_Rules.html
@@ -282,7 +285,7 @@ class EntryAci(object):
         else:
             rawaci += '!="'
         if key in self._urlkeys:
-            values = map(lambda x: 'ldap:///%s' % x, value_dict['values'])
+            values = ['ldap:///%s' % x for x in value_dict['values']]
         else:
             values = value_dict['values']
         for value in values[:-1]:
@@ -340,7 +343,7 @@ class EntryAci(object):
         return terms
 
     def _parse_term(self, key, term):
-        wdict = { 'values': [] , 'equal': True}
+        wdict = {'values': [], 'equal': True}
         # Nearly all terms are = seperated
         ## We make a dict that holds "equal" and an array of values
         pre, val = term.split('=', 1)
@@ -352,8 +355,9 @@ class EntryAci(object):
         wdict['values'] = val.split('||')
         if key in self._urlkeys:
             ### / We could replace ldap:/// in some attrs?
-            wdict['values'] = map(lambda x: x.replace('ldap:///',''), wdict['values'])
-        wdict['values'] = map(lambda x: x.strip(), wdict['values'])
+            wdict['values'] = [x.replace('ldap:///', '') for x in wdict['values']]
+        wdict['values'] = [x.strip() for x in wdict['values']]
+
         return wdict
 
     def _parse_bind_rules(self, subterm):
@@ -374,25 +378,23 @@ class EntryAci(object):
         terms = []
         bindrules = []
         interms = rawacipart.split(';')
-        interms = map(lambda x: x.strip(), interms)
+        interms = [x.strip() for x in interms]
         for iwork in interms:
             for j in self._v3keys + self._v3innerkeys:
                 if iwork.startswith(j) and j == 'acl':
                     t = iwork.split(' ', 1)[1]
                     t = t.replace('"', '')
-                    data[j].append({ 'values' : [t]})
+                    data[j].append({'values': [t]})
                 if iwork.startswith(j) and (j == 'allow' or j == 'deny'):
                     first = iwork.index('(') + 1
                     second = iwork.index(')', first)
                     # This could likely be neater ...
                     data[j].append({
-                        'values' : map( lambda x: x.strip(),
-                            iwork[first:second].split(',')
-                            )
+                        'values': [x.strip() for x in iwork[first:second].split(',')]
                         })
                     subterm = iwork[second + 1:]
                     data["%s_raw_bindrules" % j].append({
-                        'values' : self._parse_bind_rules(subterm)
+                        'values': self._parse_bind_rules(subterm)
                     })
 
         return terms
diff --git a/lib389/_ldifconn.py b/lib389/_ldifconn.py
index 1be9069..05bb6da 100644
--- a/lib389/_ldifconn.py
+++ b/lib389/_ldifconn.py
@@ -1,8 +1,10 @@
 __all__ = ['LDIFConn']
 import ldif
+import six
 from lib389._entry import Entry
 from lib389.utils import normalizeDN
 
+
 class LDIFConn(ldif.LDIFParser):
     def __init__(
         self,
@@ -19,12 +21,12 @@ class LDIFConn(ldif.LDIFParser):
         self.dndict = {}  # maps dn to Entry
         self.dnlist = []  # contains entries in order read
         myfile = input_file
-        if isinstance(input_file, basestring):
+        if isinstance(input_file, six.string_types):
             myfile = open(input_file, "r")
         ldif.LDIFParser.__init__(self, myfile, ignored_attr_types,
                                  max_entries, process_url_schemes)
         self.parse()
-        if isinstance(input_file, basestring):
+        if isinstance(input_file, six.string_types):
             myfile.close()
 
     def handle(self, dn, entry):
diff --git a/lib389/_replication.py b/lib389/_replication.py
index 2eade30..df3aa6f 100644
--- a/lib389/_replication.py
+++ b/lib389/_replication.py
@@ -1,5 +1,10 @@
 import time
 import datetime
+import logging
+import re
+
+log = logging.getLogger(__name__)
+
 
 class CSN(object):
     """CSN is Change Sequence Number
@@ -7,8 +12,7 @@ class CSN(object):
         csn.seq is the sequence number (max 65535)
         csn.rid is the replica ID of the originating master
         csn.subseq is not currently used"""
-    import re
-    import time
+
     csnpat = r'(.{8})(.{4})(.{4})(.{4})'
     csnre = re.compile(csnpat)
 
@@ -75,9 +79,6 @@ class CSN(object):
         return self.__repr__()
 
 
-
-
-
 class RUV(object):
     """RUV is Replica Update Vector
         ruv.gen is the generation CSN
@@ -93,8 +94,7 @@ class RUV(object):
         if the tryrepl flag is true, if getting the ruv from the suffix fails, try getting
         the ruv from the cn=replica entry
     """
-    import re
-    import time
+
     pre_gen = r'\{replicageneration\}\s+(\w+)'
     re_gen = re.compile(pre_gen)
     pre_ruv = r'\{replica\s+(\d+)\s+(.+?)\}\s*(\w*)\s*(\w*)'
@@ -134,7 +134,7 @@ class RUV(object):
         diff = cmp(self.gen, oth.gen)
         if diff:
             return diff
-        for rid in self.rid.keys():
+        for rid in list(self.rid.keys()):
             for item in ('max', 'min'):
                 csn = self.rid[rid][item]
                 csnoth = oth.rid[rid][item]
@@ -148,7 +148,7 @@ class RUV(object):
 
     def __str__(self):
         ret = 'generation: %s\n' % self.gen
-        for rid in self.rid.keys():
+        for rid in list(self.rid.keys()):
             ret = ret + 'rid: %s url: %s min: [%s] max: [%s]\n' % \
                 (rid, self.rid[rid]['url'], self.rid[rid].get('min', ''), self. rid[rid].get('max', ''))
         return ret
@@ -165,9 +165,10 @@ class RUV(object):
             return (1, "\tsecond RUV is empty")
         diff = cmp(self.gen, oth.gen)
         if diff:
-            return (diff, "\tgeneration [" + str(self.gen) + "] not equal to [" + str(oth.gen) + "]: likely not yet initialized")
+            return (diff, "\tgeneration [" + str(self.gen) + "] not equal to [" +
+                str(oth.gen) + "]: likely not yet initialized")
         retstr = ''
-        for rid in self.rid.keys():
+        for rid in list(self.rid.keys()):
             for item in ('max', 'min'):
                 csn = self.rid[rid][item]
                 csnoth = oth.rid[rid][item]
diff --git a/lib389/agreement.py b/lib389/agreement.py
index e94bbb2..c65e1f7 100644
--- a/lib389/agreement.py
+++ b/lib389/agreement.py
@@ -7,6 +7,7 @@ Created on Dec 5, 2013
 import ldap
 import re
 import time
+import six
 
 from lib389._constants import *
 from lib389._entry import FormatDict
@@ -207,7 +208,7 @@ class Agreement(object):
             # Build the result from the returned attributes
             for attr in entry.getAttrs():
                 # given an attribute name retrieve the property name
-                props = [k for k, v in RA_PROPNAME_TO_ATTRNAME.iteritems() if v.lower() == attr.lower()]
+                props = [k for k, v in six.iteritems(RA_PROPNAME_TO_ATTRNAME) if v.lower() == attr.lower()]
 
                 # If this attribute is present in the RA properties, adds it to result
                 if len(props) > 0:
@@ -547,7 +548,7 @@ class Agreement(object):
                 # delete the agreement
                 try:
                     self.conn.delete_s(agmts[0].dn)
-                except ldap.LDAPError, e:
+                except ldap.LDAPError as e:
                     self.log.error('Failed to delete agreement (%s), error: %s' %
                         (agmts[0].dn, e.message['desc']))
                     raise ldap.LDAPError
diff --git a/lib389/backend.py b/lib389/backend.py
index c341a26..5d2a197 100644
--- a/lib389/backend.py
+++ b/lib389/backend.py
@@ -8,12 +8,13 @@ import ldap
 from lib389 import DirSrv, Entry, NoSuchEntryError, InvalidArgumentError
 from lib389._constants import *
 from lib389.utils import (
-    normalizeDN, 
+    normalizeDN,
     suffixfilt
     )
 from compiler.ast import Not
 from lib389.properties import *
-from __init__ import UnwillingToPerformError
+from .__init__ import UnwillingToPerformError
+
 
 class Backend(object):
     proxied_methods = 'search_s getEntry'.split()
@@ -33,19 +34,19 @@ class Backend(object):
 
             If 'suffix'/'backend_dn'/'benamebase' are specified. It uses 'backend_dn' first, then 'suffix', then 'benamebase'.
 
-            If neither 'suffix', 'backend_dn' and 'benamebase' are specified, it returns all the backend entries 
-            
+            If neither 'suffix', 'backend_dn' and 'benamebase' are specified, it returns all the backend entries
+
             Get backends by name or suffix
-            
+
             @param suffix - suffix of the backend
             @param backend_dn - DN of the backend entry
             @param bename - 'commonname'/'cn' of the backend (e.g. 'userRoot')
-            
+
             @return backend entries
-            
+
             @raise None
         """
-        
+
         filt = "(objectclass=%s)" % BACKEND_OBJECTCLASS_VALUE
         if backend_dn:
             self.log.info("List backend %s" % backend_dn)
@@ -66,15 +67,15 @@ class Backend(object):
             self.log.info("List all the backends")
             base = DN_PLUGIN
             scope = ldap.SCOPE_SUBTREE
-            
+
         try:
             ents = self.conn.search_s(base, scope, filt)
         except ldap.NO_SUCH_OBJECT:
             return None
-        
+
         return ents
-                                  
-        
+
+
     def _readonly(self, bename=None, readonly='on', suffix=None):
         """Put a database in readonly mode
             @param  bename  -   the backend name (eg. addressbook1)
@@ -82,9 +83,9 @@ class Backend(object):
 
             NOTE: I can ldif2db to a read-only database. After the
                   import, the database will still be in readonly.
-                  
-            NOTE: When a db is read-only, it seems you need to restart 
-                  the directory server before creating further 
+
+            NOTE: When a db is read-only, it seems you need to restart
+                  the directory server before creating further
                   agreements or initialize consumers
         """
         if bename and suffix:
@@ -96,36 +97,36 @@ class Backend(object):
         self.conn.modify_s(','.join(('cn=' + bename, DN_LDBM)), [
             (ldap.MOD_REPLACE, BACKEND_PROPNAME_TO_ATTRNAME[BACKEND_READONLY], readonly)
         ])
-        
-        
+
+
     def delete(self, suffix=None, backend_dn=None, bename=None):
         """
         Deletes the backend entry with the following steps:
 
         Delete the indexes entries under this backend
         Delete the encrypted attributes entries under this backend
-        Delete the encrypted attributes keys entries under this backend 
+        Delete the encrypted attributes keys entries under this backend
 
         If a mapping tree entry uses this backend (nsslapd-backend), it raise UnwillingToPerformError
-        
-        If 'suffix'/'backend_dn'/'benamebase' are specified. 
+
+        If 'suffix'/'backend_dn'/'benamebase' are specified.
         It uses 'backend_dn' first, then 'suffix', then 'benamebase'.
-        
-        If neither 'suffix', 'backend_dn' and 'benamebase' are specified, it raise InvalidArgumentError 
+
+        If neither 'suffix', 'backend_dn' and 'benamebase' are specified, it raise InvalidArgumentError
         @param suffix - suffix of the backend
         @param backend_dn - DN of the backend entry
         @param bename - 'commonname'/'cn' of the backend (e.g. 'userRoot')
-        
+
         @return None
-        
+
         @raise InvalidArgumentError - if missing arguments or invalid
                 UnwillingToPerformError - if several backends match the argument
                                      provided suffix does not match backend suffix
                                      It exists a mapping tree that use that backend
-        
-        
+
+
         """
-        
+
         # First check the backend exists and retrieved its suffix
         be_ents = self.conn.backend.list(suffix=suffix, backend_dn=backend_dn, bename=bename)
         if len(be_ents) == 0:
@@ -139,47 +140,47 @@ class Backend(object):
         else:
             be_ent = be_ents[0]
             be_suffix = be_ent.getValue(BACKEND_PROPNAME_TO_ATTRNAME[BACKEND_SUFFIX])
-            
+
         # Verify the provided suffix is the one stored in the found backend
         if suffix:
             if normalizeDN(suffix) != normalizeDN(be_suffix):
                 raise UnwillingToPerformError("provided suffix (%s) differs from backend suffix (%s)" % (suffix, be_suffix))
-        
+
         # now check there is no mapping tree for that suffix
         mt_ents = self.conn.mappingtree.list(suffix=be_suffix)
         if len(mt_ents) > 0:
             raise UnwillingToPerformError("It still exists a mapping tree (%s) for that backend (%s)" % (mt_ents[0].dn, be_ent.dn))
-            
+
         # Now delete the indexes
         found_bename = be_ent.getValue(BACKEND_PROPNAME_TO_ATTRNAME[BACKEND_NAME])
         if not bename:
             bename = found_bename
         elif bename != found_bename:
             raise UnwillingToPerformError("Backend name specified (%s) differs from the retrieved one (%s)" % (bename, found_bename))
-        
+
         self.conn.index.delete_all(bename)
-        
+
         # finally delete the backend children and the backend itself
         ents = self.conn.search_s(be_ent.dn, ldap.SCOPE_ONELEVEL)
         for ent in ents:
             self.log.debug("Delete entry children %s" % (ent.dn))
             self.conn.delete_s(ent.dn)
-            
+
         self.log.debug("Delete backend entry %s" % (be_ent.dn))
         self.conn.delete_s(be_ent.dn)
-            
+
         return
 
     def create(self, suffix=None, properties=None):
         """
-            Creates backend entry and returns its dn. 
-            
-            If the properties 'chain-bind-pwd' and 'chain-bind-dn' and 'chain-urls' are specified 
-            the backend is a chained backend. 
-            A chaining backend is created under 'cn=chaining database,cn=plugins,cn=config'. 
-            
-            A local backend is created under 'cn=ldbm database,cn=plugins,cn=config' 
-            
+            Creates backend entry and returns its dn.
+
+            If the properties 'chain-bind-pwd' and 'chain-bind-dn' and 'chain-urls' are specified
+            the backend is a chained backend.
+            A chaining backend is created under 'cn=chaining database,cn=plugins,cn=config'.
+
+            A local backend is created under 'cn=ldbm database,cn=plugins,cn=config'
+
             @param suffix - suffix stored in the backend
             @param properties - dictionary with properties values
             supported properties are
@@ -194,10 +195,10 @@ class Backend(object):
                 BACKEND_CHAIN_BIND_DN = 'chain-bind-dn'
                 BACKEND_CHAIN_BIND_PW = 'chain-bind-pw'
                 BACKEND_CHAIN_URLS    = 'chain-urls'
-                
+
             @return backend DN of the created backend
-            
-            @raise ValueError - If missing suffix 
+
+            @raise ValueError - If missing suffix
                     InvalidArgumentError - If it already exists a backend for that suffix or a backend with the same DN
 
         """
@@ -218,18 +219,18 @@ class Backend(object):
                     self.log.info("backend name will be %s" % bename)
                     return bename
                 index += 1
-                
+
         # suffix is mandatory
         if not suffix:
             raise ValueError("suffix is mandatory")
         else:
             nsuffix = normalizeDN(suffix)
-        
+
         # Check it does not already exist a backend for that suffix
         ents = self.conn.backend.list(suffix=suffix)
         if len(ents) != 0:
             raise InvalidArgumentError("It already exists backend(s) for %s: %s" % (suffix, ents[0].dn))
-        
+
         # Check if we are creating a local/chained backend
         chained_suffix = properties and (BACKEND_CHAIN_BIND_DN in properties) and (BACKEND_CHAIN_BIND_PW in properties) and (BACKEND_CHAIN_URLS in properties)
         if chained_suffix:
@@ -238,21 +239,21 @@ class Backend(object):
         else:
             self.log.info("Creating a local backend")
             dnbase = DN_LDBM
-        
+
         # Get the future backend name
         if properties and BACKEND_NAME in properties:
             cn = properties[BACKEND_NAME]
         else:
             cn = _getBackendName(dnbase)
-        
+
         # Check the future backend name does not already exists
-        # we can imagine having no backends for 'suffix' but having a backend 
+        # we can imagine having no backends for 'suffix' but having a backend
         # with the same name
         dn = "%s=%s,%s" % (BACKEND_PROPNAME_TO_ATTRNAME[BACKEND_NAME], cn, dnbase)
         ents = self.conn.backend.list(backend_dn=dn)
         if ents:
             raise InvalidArgumentError("It already exists a backend with that DN: %s" % ents[0].dn)
-        
+
         # All checks are done, Time to create the backend
         try:
             entry = Entry(dn)
@@ -261,7 +262,7 @@ class Backend(object):
                 BACKEND_PROPNAME_TO_ATTRNAME[BACKEND_NAME]: cn,
                 BACKEND_PROPNAME_TO_ATTRNAME[BACKEND_SUFFIX]: nsuffix
             })
-            
+
             if chained_suffix:
                 entry.update({
                              BACKEND_PROPNAME_TO_ATTRNAME[BACKEND_CHAIN_URLS]:    properties[BACKEND_CHAIN_URLS],
@@ -271,34 +272,33 @@ class Backend(object):
 
             self.log.debug("adding entry: %r" % entry)
             self.conn.add_s(entry)
-        except ldap.ALREADY_EXISTS, e:
+        except ldap.ALREADY_EXISTS as e:
             self.log.error("Entry already exists: %r" % dn)
             raise ldap.ALREADY_EXISTS("%s : %r" % (e, dn))
-        except ldap.LDAPError, e:
+        except ldap.LDAPError as e:
             self.log.error("Could not add backend entry: %r" % dn)
 
-
         backend_entry = self.conn._test_entry(dn, ldap.SCOPE_BASE)
-        
+
         return backend_entry
-    
+
     def getProperties(self, suffix=None, backend_dn=None, bename=None, properties=None):
         raise NotImplemented
-    
-    def setProperties(self,suffix=None, backend_dn=None, bename=None, properties=None):
+
+    def setProperties(self, suffix=None, backend_dn=None, bename=None, properties=None):
         raise NotImplemented
-    
+
     def toSuffix(self, entry=None, name=None):
         '''
             Return, for a given backend entry, the suffix values.
             Suffix values are identical from a LDAP point of views. Suffix values may
             be surrounded by ", or containing '\' escape characters.
-            
+
             @param entry - LDAP entry of the backend
             @param name  - backend DN
-            
+
             @result list of values of suffix attribute (aka 'cn')
-            
+
             @raise ldap.NO_SUCH_OBJECT - in name is invalid DN
                    ValueError - entry does not contains the suffix attribute
                    InvalidArgumentError - if both entry/name are missing
@@ -310,20 +310,20 @@ class Backend(object):
             return entry.getValues(attr_suffix)
         elif name:
             filt = "(objectclass=%s)" % BACKEND_OBJECTCLASS_VALUE
-            
+
             try:
                 attrs = [attr_suffix]
                 ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt, attrs)
                 self.log.debug("toSuffix: %s found by its DN" % ent.dn)
             except NoSuchEntryError:
                 raise ldap.NO_SUCH_OBJECT("Backend DN not found: %s" % name)
-            
+
             if not ent.hasValue(attr_suffix):
                 raise ValueError("Entry has no %s attribute %r" % (attr_suffix, ent))
             return ent.getValues(attr_suffix)
         else:
             raise InvalidArgumentError("entry or name are mandatory")
-        
+
     def requireIndex(self, suffix):
         '''
         Should be moved in setProperties
diff --git a/lib389/changelog.py b/lib389/changelog.py
index 025e71e..fd4815d 100644
--- a/lib389/changelog.py
+++ b/lib389/changelog.py
@@ -64,7 +64,7 @@ class Changelog(object):
         '''
         try:
             self.conn.delete_s(DN_CHANGELOG)
-        except ldap.LDAPError, e:
+        except ldap.LDAPError as e:
             self.log.error('Failed to delete the changelog: ' + e.message['desc'])
             raise ldap.LDAPError
 
diff --git a/lib389/ds_instance.py b/lib389/ds_instance.py
index 7545eee..1f14035 100644
--- a/lib389/ds_instance.py
+++ b/lib389/ds_instance.py
@@ -1,10 +1,14 @@
-import os, re, sys
+import os
+import re
+import sys
+import collections
+
 
 class DSDecorator(object):
     """ Implements decorator that can be instantiated during runtime.
 
         Accepts function and instance of DSInstance. When called,
-        it will call passed function with instance of DSInstance 
+        it will call passed function with instance of DSInstance
         passed as the first argument.
     """
     def __init__(self, fun, ds_instance):
@@ -21,14 +25,15 @@ class DSDecorator(object):
         else:
             return self.fun(self.ds_instance, *args, **kwargs)
 
+
 class DSModuleProxy(object):
     """ Proxy with DS-decorated functions from modules in directory.
 
         DSModuleProxy object acts as a proxy to functions defined in modules
-        stored in directory. Proxy itself can have other proxies as 
-        attributes, so returned object follows the structure of passed 
-        directory. All funcions from all modules are decorated with 
-        DSDecorator - DSInstance object will be passed to them as first 
+        stored in directory. Proxy itself can have other proxies as
+        attributes, so returned object follows the structure of passed
+        directory. All funcions from all modules are decorated with
+        DSDecorator - DSInstance object will be passed to them as first
         argument.
 
         Kudos to Milan Falesnik <mfalesni@redhat.com>
@@ -56,10 +61,10 @@ class DSModuleProxy(object):
             # case when item is python module
             elif (os.path.isfile(directory + "/" + item) and
                     re.match(r'(.*\/)?[^_/].*[^_/]\.py$', item)):
-            
+
                 # get the module object corresponding to processed file
                 item = item.replace('.py', '')
-                to_import = (directory + "/" + item).replace('/','.')
+                to_import = (directory + "/" + item).replace('/', '.')
                 __import__(to_import)
                 module = sys.modules[to_import]
                 proxy = cls(item)
@@ -67,7 +72,7 @@ class DSModuleProxy(object):
                 # for each function from module create decorated one and keep it
                 for attr in dir(module):
                     fun = getattr(module, attr)
-                    if callable(fun):
+                    if isinstance(fun, collections.Callable):
                         decorated = DSDecorator(fun, ds)
                         setattr(proxy, attr, decorated)
                 setattr(obj, item, proxy)
@@ -76,6 +81,7 @@ class DSModuleProxy(object):
                 # skip anything that is not directory or python module
                 pass
 
+
 class DSInstance(object):
 
     def __init__(self):
diff --git a/lib389/index.py b/lib389/index.py
index fdd8c6b..0a0f69e 100644
--- a/lib389/index.py
+++ b/lib389/index.py
@@ -11,38 +11,36 @@ from lib389 import Entry
 
 
 class Index(object):
-    
+
     def __init__(self, conn):
         """@param conn - a DirSrv instance"""
         self.conn = conn
         self.log = conn.log
-    
+
     def delete_all(self, benamebase):
         dn = "cn=index,cn=" + benamebase + "," + DN_LDBM
-        
+
         # delete each defined index
         ents = self.conn.search_s(dn, ldap.SCOPE_ONELEVEL)
         for ent in ents:
             self.log.debug("Delete index entry %s" % (ent.dn))
             self.conn.delete_s(ent.dn)
-            
+
         # Then delete the top index entry
         self.log.debug("Delete head index entry %s" % (dn))
         self.conn.delete_s(dn)
-    
+
     def create(self, suffix=None, attr=None, args=None):
         if not suffix:
             raise ValueError("suffix is mandatory parameter")
-        
+
         if not attr:
             raise ValueError("attr is mandatory parameter")
-        
+
         indexTypes = args.get(INDEX_TYPE, None)
         matchingRules = args.get(INDEX_MATCHING_RULE, None)
-        
+
         self.addIndex(suffix, attr, indexTypes=indexTypes, matchingRules=matchingRules)
-        
-        
 
     def addIndex(self, suffix, attr, indexTypes, matchingRules):
         """Specify the suffix (should contain 1 local database backend),
@@ -62,8 +60,7 @@ class Index(object):
         try:
             self.conn.add_s(entry)
         except ldap.ALREADY_EXISTS:
-            print "Index for attr %s for backend %s already exists" % (
-                attr, dn)
+            print("Index for attr %s for backend %s already exists" % (attr, dn))
 
     def modIndex(self, suffix, attr, mod):
         """just a wrapper around a plain old ldap modify, but will
diff --git a/lib389/mappingTree.py b/lib389/mappingTree.py
index c4224fb..72aacdc 100644
--- a/lib389/mappingTree.py
+++ b/lib389/mappingTree.py
@@ -5,6 +5,7 @@ Created on Dec 13, 2013
 '''
 
 import ldap
+import six
 
 from lib389 import DirSrv, Entry, NoSuchEntryError, UnwillingToPerformError, InvalidArgumentError
 from lib389._constants import *
@@ -14,12 +15,12 @@ from lib389.utils import (
     )
 from lib389.properties import *
 
+
 class MappingTree(object):
     '''
     classdocs
     '''
 
-
     proxied_methods = 'search_s getEntry'.split()
 
     def __init__(self, conn):
@@ -53,31 +54,30 @@ class MappingTree(object):
             filt = "(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX], suffix)
         else:
             filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE
-        
+
         try:
             ents = self.conn.search_s(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL, filt)
             for ent in ents:
                 self.log.debug('list: %r' % ent)
         except:
             raise
-        
+
         return ents
-    
-    
+
     def create(self, suffix=None, bename=None, parent=None):
         '''
-            Create a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' 
-            and that is stored in 'bename' backend. 
-            'bename' backend must exists before creating the mapping tree entry. 
-            
+            Create a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix'
+            and that is stored in 'bename' backend.
+            'bename' backend must exists before creating the mapping tree entry.
+
             If a 'parent' is provided that means that we are creating a sub-suffix mapping tree.
 
             @param suffix - suffix mapped by this mapping tree entry. It will be the common name ('cn') of the entry
             @param benamebase - backend common name (e.g. 'userRoot')
             @param parent - if provided is a parent suffix of 'suffix'
-            
+
             @return DN of the mapping tree entry
-            
+
             @raise ldap.NO_SUCH_OBJECT - if the backend entry or parent mapping tree does not exist
 
         '''
@@ -86,11 +86,11 @@ class MappingTree(object):
             raise ValueError("suffix is mandatory")
         else:
             nsuffix = normalizeDN(suffix)
-        
+
         # Check backend name is provided
         if not bename:
             raise ValueError("backend name is mandatory")
-        
+
         # Check that if the parent suffix is provided then
         # it exists a mapping tree for it
         if parent:
@@ -103,7 +103,7 @@ class MappingTree(object):
                 raise ValueError("parent suffix has no mapping tree")
         else:
             nparent = ""
-            
+
         # Check if suffix exists, return
         filt = suffixfilt(suffix)
         try:
@@ -112,10 +112,10 @@ class MappingTree(object):
         except NoSuchEntryError:
             entry = None
 
-        # 
+        #
         # Now start the real work
         #
-        
+
         # fix me when we can actually used escaped DNs
         dn = ','.join(('cn="%s"' % nsuffix, DN_MAPPING_TREE))
         entry = Entry(dn)
@@ -127,36 +127,36 @@ class MappingTree(object):
             MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]: nsuffix,
             MT_PROPNAME_TO_ATTRNAME[MT_BACKEND]: bename
         })
-        
+
         # possibly add the parent
         if parent:
             entry.setValues(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX], nparent)
-            
+
         try:
             self.log.debug("Creating entry: %s" % entry.dn)
             self.log.info("Entry %r" % entry)
             self.conn.add_s(entry)
-        except ldap.LDAPError, e:
+        except ldap.LDAPError as e:
             raise ldap.LDAPError("Error adding suffix entry " + dn, e)
 
         ret = self.conn._test_entry(dn, ldap.SCOPE_BASE)
         return ret.dn
-    
+
     def delete(self, suffix=None, bename=None, name=None):
         '''
-            Delete a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' and 
-            that is stored in 'benamebase' backend. 
+            Delete a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' and
+            that is stored in 'benamebase' backend.
             'benamebase' backend is not changed by the mapping tree deletion.
 
-            If 'name' is specified. It uses it to retrieve the mapping tree to delete 
-            Else if 'suffix'/'benamebase' are specified. It uses both to retrieve the mapping tree to delete 
+            If 'name' is specified. It uses it to retrieve the mapping tree to delete
+            Else if 'suffix'/'benamebase' are specified. It uses both to retrieve the mapping tree to delete
 
             @param suffix - suffix mapped by this mapping tree entry. It is the common name ('cn') of the entry
             @param benamebase - backend common name (e.g. 'userRoot')
             @param name - DN of the mapping tree entry
-            
+
             @return None
-            
+
             @raise ldap.NO_SUCH_OBJECT - the entry is not found
                          KeyError if 'name', 'suffix' and 'benamebase' are missing
                    UnwillingToPerformError - If the mapping tree has subordinates
@@ -169,27 +169,27 @@ class MappingTree(object):
             except NoSuchEntryError:
                 raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name)
         else:
-            filt=None
-            
+            filt = None
+
             if suffix:
                 filt = suffixfilt(suffix)
-                
+
             if bename:
                 if filt:
                     filt = "(&(%s=%s)%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename, filt)
                 else:
                     filt = "(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename)
-            
+
             try:
                 ent = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL, filt)
                 self.log.debug("delete: %s found by with %s" % (ent.dn, filt))
             except NoSuchEntryError:
                 raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name)
-         
-        #   
+
+        #
         # At this point 'ent' contains the mapping tree entry to delete
         #
-        
+
         # First Check there is no child (replica, replica agreements)
         try:
             ents = self.conn.search_s(ent.dn, ldap.SCOPE_SUBTREE, "objectclass=*")
@@ -206,72 +206,72 @@ class MappingTree(object):
 
     def getProperties(self, suffix=None, bename=None, name=None, properties=None):
         '''
-            Returns a dictionary of the requested properties. 
+            Returns a dictionary of the requested properties.
             If properties is missing, it returns all the properties.
 
             The returned properties are those of the 'suffix' and that is stored in 'benamebase' backend.
 
             If 'name' is specified. It uses it to retrieve the mapping tree to delete Else if 'suffix'/'benamebase' are specified. It uses both to retrieve the mapping tree to
 
-            If 'name', 'benamebase' and 'suffix' are missing it raise an exception 
-            
+            If 'name', 'benamebase' and 'suffix' are missing it raise an exception
+
             @param suffix - suffix mapped by this mapping tree entry. It is the common name ('cn') of the entry
             @param benamebase - backend common name (e.g. 'userRoot')
             @param name - DN of the mapping tree entry
             @param - properties - list of properties
-            
+
             @return - returns a dictionary of the properties
-            
+
             @raise ValueError - if some name of properties are not valid
                    KeyError   - if some name of properties are not valid
                    ldap.NO_SUCH_OBJECT - if the mapping tree entry is not found
         '''
-        
+
         if name:
             filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE
-            
+
             try:
-                ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt, MT_PROPNAME_TO_ATTRNAME.values())
+                ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt, list(MT_PROPNAME_TO_ATTRNAME.values()))
                 self.log.debug("delete: %s found by its DN" % ent.dn)
             except NoSuchEntryError:
                 raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name)
         else:
-            filt=None
-            
+            filt = None
+
             if suffix:
                 filt = suffixfilt(suffix)
-                
+
             if bename:
                 if filt:
                     filt = "(&(%s=%s)%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename, filt)
                 else:
                     filt = "(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename)
-            
+
             try:
-                ent = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL, filt, MT_PROPNAME_TO_ATTRNAME.values())
+                ent = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL,
+                                         filt, list(MT_PROPNAME_TO_ATTRNAME.values()))
                 self.log.debug("delete: %s found by with %s" % (ent.dn, filt))
             except NoSuchEntryError:
                 raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name)
 
-        
         result = {}
         attrs = []
         if properties:
             #
             # build the list of attributes we are looking for
-            
+
             for prop_name in properties:
                 prop_attr = MT_PROPNAME_TO_ATTRNAME[prop_name]
                 if not prop_attr:
                     raise ValueError("Improper property name: %s ", prop_name)
                 self.log.debug("Look for attr %s (property: %s)" % (prop_attr, prop_name))
                 attrs.append(prop_attr)
-           
-        # now look for each attribute from the MT entry 
+
+        # now look for each attribute from the MT entry
         for attr in ent.getAttrs():
             # given an attribute name retrieve the property name
-            props = [ k for k, v in MT_PROPNAME_TO_ATTRNAME.iteritems() if v.lower() == attr.lower() ]
-            
+            props = [k for k, v in six.iteritems(MT_PROPNAME_TO_ATTRNAME) if v.lower() == attr.lower()]
+
             # If this attribute is present in the MT properties and was requested, adds it to result
             if len(props) > 0:
                 if len(attrs) > 0:
@@ -282,21 +282,21 @@ class MappingTree(object):
                 else:
                     result[props[0]] = ent.getValues(attr)
         return result
-    
+
     def setProperties(self, suffix=None, bename=None, name=None, properties=None):
         raise NotImplemented()
-                
+
     def toSuffix(self, entry=None, name=None):
         '''
             Return, for a given mapping tree entry, the suffix values.
             Suffix values are identical from a LDAP point of views. Suffix values may
             be surrounded by ", or containing '\' escape characters.
-            
+
             @param entry - LDAP entry of the mapping tree
             @param name  - mapping tree DN
-            
+
             @result list of values of suffix attribute (aka 'cn')
-            
+
             @raise ldap.NO_SUCH_OBJECT - in name is invalid DN
                    ValueError - entry does not contains the suffix attribute
                    InvalidArgumentError - if both entry/name are missing
@@ -308,14 +308,14 @@ class MappingTree(object):
             return entry.getValues(attr_suffix)
         elif name:
             filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE
-            
+
             try:
                 attrs = [attr_suffix]
                 ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt, attrs)
                 self.log.debug("toSuffix: %s found by its DN" % ent.dn)
             except NoSuchEntryError:
                 raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name)
-            
+
             if not ent.hasValue(attr_suffix):
                 raise ValueError("Entry has no %s attribute %r" % (attr_suffix, ent))
             return ent.getValues(attr_suffix)
diff --git a/lib389/replica.py b/lib389/replica.py
index f49cdc7..4d71f70 100644
--- a/lib389/replica.py
+++ b/lib389/replica.py
@@ -355,11 +355,11 @@ class Replica(object):
             for agmt in agmts:
                 try:
                     self.conn.delete_s(agmt.dn)
-                except ldap.LDAPError, e:
+                except ldap.LDAPError as e:
                     self.log.fatal('Failed to delete replica agreement (%s), error: %s' %
                         (admt.dn, e.message('desc')))
                     raise ldap.LDAPError
-        except ldap.LDAPError, e:
+        except ldap.LDAPError as e:
             self.log.fatal('Failed to search for replication agreements under (%s), error: %s' %
                 (dn_replica, e.message('desc')))
             raise ldap.LDAPError
@@ -393,21 +393,21 @@ class Replica(object):
         # Delete the agreements
         try:
             self.deleteAgreements(nsuffix)
-        except ldap.LDAPError, e:
+        except ldap.LDAPError as e:
             self.log.fatal('Failed to delete replica agreements!')
             raise ldap.LDAPError
 
         # Delete the replica
         try:
             self.conn.delete_s(dn_replica)
-        except ldap.LDAPError, e:
+        except ldap.LDAPError as e:
             self.log.fatal('Failed to delete replica configuration (%s), error: %s' % (dn_replica, e.message('desc')))
             raise ldap.LDAPError
 
         # Delete the changelog
         try:
             self.conn.changelog.delete()
-        except ldap.LDAPError, e:
+        except ldap.LDAPError as e:
             self.log.error('Failed to delete changelog: ' + e.message['desc'])
             raise ldap.LDAPError
 
@@ -503,22 +503,22 @@ class Replica(object):
             status = entry.nsds5ReplicaLastInitStatus
             if not refresh:  # done - check status
                 if not status:
-                    print "No status yet"
+                    print("No status yet")
                 elif status.find("replica busy") > -1:
-                    print "Update failed - replica busy - status", status
+                    print("Update failed - replica busy - status", status)
                     done = True
                     hasError = 2
                 elif status.find("Total update succeeded") > -1:
-                    print "Update succeeded: status ", status
+                    print("Update succeeded: status ", status)
                     done = True
                 elif inprogress.lower() == 'true':
-                    print "Update in progress yet not in progress: status ", status
+                    print("Update in progress yet not in progress: status ", status)
                 else:
-                    print "Update failed: status", status
+                    print("Update failed: status", status)
                     hasError = 1
                     done = True
             elif self.verbose:
-                print "Update in progress: status", status
+                print("Update in progress: status", status)
 
         return done, hasError
 
diff --git a/lib389/schema.py b/lib389/schema.py
index 4dc9634..e4821a6 100644
--- a/lib389/schema.py
+++ b/lib389/schema.py
@@ -8,19 +8,20 @@ import os
 import re
 import time
 import glob
-
+import six
 
 from lib389._constants import *
 from lib389 import Entry
 from lib389.utils import normalizeDN, escapeDNValue, suffixfilt
 
+
 class Schema(object):
-    
+
     def __init__(self, conn):
         """@param conn - a DirSrv instance"""
         self.conn = conn
         self.log = conn.log
-    
+
     def get_entry(self):
         """get the schema as an LDAP entry"""
         attrs = ['attributeTypes', 'objectClasses']
@@ -38,9 +39,12 @@ class Schema(object):
         """convert the given schema file name to its python-ldap format
         suitable for passing to ldap.schema.SubSchema()
         @param filename - the full path and filename of a schema file in ldif format"""
-        import urllib,ldif
-        ldif_file = urllib.urlopen(filename)
-        ldif_parser = ldif.LDIFRecordList(ldif_file,max_entries=1)
+        import six.moves.urllib.request
+        import six.moves.urllib.parse
+        import ldif
+
+        ldif_file = six.moves.urllib.request.urlopen('file://' + filename)
+        ldif_parser = ldif.LDIFRecordList(ldif_file, max_entries=1)
         if not ldif_parser:
             return None
         ldif_parser.parse()
@@ -62,7 +66,7 @@ class Schema(object):
         @param attr the attribute type to use e.g. attributeTypes or objectClasses
         @param val the schema element definition to add"""
         self.conn.modify_s(DN_SCHEMA, [(ldap.MOD_ADD, attr, val)])
-        
+
     def del_schema(self, attr, val):
         """Delete a schema element from the schema.
         @param attr the attribute type to use e.g. attributeTypes or objectClasses
@@ -78,7 +82,7 @@ class Schema(object):
         """Add an object class definition to the schema.
         @param objectclasses a single or list of object class defintions to add"""
         return self.add_schema('objectClasses', objectclasses)
-    
+
     def get_schema_csn(self):
         """return the schema nsSchemaCSN attribute"""
         ents = self.conn.search_s(DN_SCHEMA, ldap.SCOPE_BASE, "objectclass=*", ['nsSchemaCSN'])
@@ -90,7 +94,7 @@ class Schema(object):
         """
         attrs = ['objectClasses']
         results = self.conn.search_s(DN_SCHEMA, ldap.SCOPE_BASE, 'objectclass=*', attrs)[0]
-        objectclasses = map(lambda oc: ObjectClass(oc), results.getValues('objectClasses'))
+        objectclasses = [ObjectClass(oc) for oc in results.getValues('objectClasses')]
         return objectclasses
 
     def get_attributetypes(self):
@@ -98,7 +102,7 @@ class Schema(object):
         """
         attrs = ['attributeTypes']
         results = self.conn.search_s(DN_SCHEMA, ldap.SCOPE_BASE, 'objectclass=*', attrs)[0]
-        attributetypes = map(lambda at: AttributeType(at), results.getValues('attributeTypes'))
+        attributetypes = [AttributeType(at) for at in results.getValues('attributeTypes')]
         return attributetypes
 
     def query_objectclass(self, objectclassname):
@@ -112,7 +116,7 @@ class Schema(object):
         <ldap.schema.models.ObjectClass instance>
         """
         objectclasses = self.get_objectclasses()
-        objectclass = filter(lambda oc: objectclassname in oc.names, objectclasses)
+        objectclass = [oc for oc in objectclasses if objectclassname in oc.names]
         if len(objectclass) != 1:
             #This is an error.
             return None
@@ -135,7 +139,7 @@ class Schema(object):
         attributetypes = self.get_attributetypes()
         attributetypename = attributetypename.lower()
 
-        attributetype = filter(lambda at: attributetypename in at.names, attributetypes)
+        attributetype = [at for at in attributetypes if attributetypename in at.names]
         if len(attributetype) != 1:
             #This is an error.
             return None
@@ -143,7 +147,7 @@ class Schema(object):
         # Get the primary name of this attribute
         attributetypename = attributetype.names[0]
         # Build a set if they have may.
-        may = filter(lambda oc: attributetypename in oc.may, objectclasses)
+        may = [oc for oc in objectclasses if attributetypename in oc.may]
         # Build a set if they have must.
-        must = filter(lambda oc: attributetypename in oc.must, objectclasses)
+        must = [oc for oc in objectclasses if attributetypename in oc.must]
         return (attributetype, must, may)
diff --git a/lib389/tools.py b/lib389/tools.py
index 3e84745..a61d5d5 100644
--- a/lib389/tools.py
+++ b/lib389/tools.py
@@ -14,8 +14,9 @@ import sys
 import os
 import os.path
 import base64
-import urllib
-import urllib2
+import six.moves.urllib.request
+import six.moves.urllib.parse
+import six.moves.urllib.error
 import ldap
 import operator
 import select
@@ -64,7 +65,7 @@ class DirSrvTools(object):
     @staticmethod
     def cgiFake(sroot, verbose, prog, args):
         """Run the local program prog as a CGI using the POST method."""
-        content = urllib.urlencode(args)
+        content = urllib.parse.urlencode(args)
         length = len(content)
         # setup CGI environment
         env = os.environ.copy()
@@ -94,8 +95,8 @@ class DirSrvTools(object):
         child_stdout.close()
         if HASPOPEN:
             osCode = pipe.wait()
-            print "%s returned NMC code %s and OS code %s" % (
-                prog, exitCode, osCode)
+            print("%s returned NMC code %s and OS code %s" %
+                (prog, exitCode, osCode))
         return exitCode
 
     @staticmethod
@@ -120,24 +121,24 @@ class DirSrvTools(object):
         savedbinsize = base64.MAXBINSIZE
         base64.MAXBINSIZE = 256
         # create the password manager - we don't care about the realm
-        passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
+        passman = urllib.request.HTTPPasswordMgrWithDefaultRealm()
         # add our password
         passman.add_password(None, hostport, username, password)
         # create the auth handler
-        authhandler = urllib2.HTTPBasicAuthHandler(passman)
+        authhandler = urllib.request.HTTPBasicAuthHandler(passman)
         # create our url opener that handles basic auth
-        opener = urllib2.build_opener(authhandler)
+        opener = urllib.request.build_opener(authhandler)
         # make admin server think we are the console
         opener.addheaders = [('User-Agent', 'Fedora-Console/1.0')]
         if verbose:
-            print "requesting url", url
+            print("requesting url", url)
             sys.stdout.flush()
         exitCode = 1
         try:
-            req = opener.open(url, urllib.urlencode(args))
+            req = opener.open(url, urllib.parse.urlencode(args))
             for line in req:
                 if verbose:
-                    print line
+                    print (line)
                 ary = line.split(":")
                 if len(ary) > 1 and ary[0] == 'NMC_Status':
                     exitCode = ary[1].strip()
@@ -513,10 +514,10 @@ class DirSrvTools(object):
                 try:
                     log.info("Copying security files: %s to %s" % (srcf, destf))
                     mode = os.stat(destf).st_mode
-                    newmode = mode | 0600
+                    newmode = mode | 0o600
                     os.chmod(destf, newmode)
-                except Exception, e:
-                    print e
+                except Exception as e:
+                    print(e)
                     pass  # oh well
                 # copy2 will copy the mode too
                 shutil.copy2(srcf, destf)
@@ -553,7 +554,7 @@ class DirSrvTools(object):
                 if verbose:
                     sys.stdout.write(line)
             elif verbose:
-                print "timed out waiting to read from", cmd
+                print("timed out waiting to read from", cmd)
         child_stdout.close()
         exitCode = pipe.wait()
         #if verbose:
@@ -744,8 +745,8 @@ class DirSrvTools(object):
                 newconn.asport = asport
                 newconn.cfgdsuser = args['cfgdsuser']
                 newconn.cfgdspwd = args['cfgdspwd']
-            print "Warning: server at %s:%s already exists, returning connection to it" % \
-                  (args['newhost'], args['newport'])
+            print("Warning: server at %s:%s already exists, returning connection to it" %
+                  (args['newhost'], args['newport']))
             return newconn
         except ldap.SERVER_DOWN:
             pass  # not running - create new one
@@ -753,10 +754,10 @@ class DirSrvTools(object):
         if not isLocal or 'cfgdshost' in args:
             for param in ('cfgdshost', 'cfgdsport', 'cfgdsuser', 'cfgdspwd', 'admin_domain'):
                 if param not in args:
-                    print "missing required argument", param
+                    print("missing required argument", param)
                     missing = True
         if not isLocal and not asport:
-            print "missing required argument admin server port"
+            print("missing required argument admin server port")
             missing = True
         if missing:
             raise InvalidArgumentError("missing required arguments")
@@ -824,7 +825,7 @@ class DirSrvTools(object):
         # the second is a dict suitable for replicaSetupAll - see replicaSetupAll
         conn = DirSrvTools.createInstance(createArgs)
         if not conn:
-            print "Error: could not create server", createArgs
+            print("Error: could not create server", createArgs)
             return 0
 
         conn.replicaSetupAll(repArgs)
@@ -834,9 +835,9 @@ class DirSrvTools(object):
     def makeGroup(group=DEFAULT_USER):
         try:
             grp.getgrnam(group)
-            print "OK group %s exists" % group
+            print("OK group %s exists" % group)
         except KeyError:
-            print "Adding group %s" % group
+            print("Adding group %s" % group)
             cmd = [GROUPADD, '-r', group]
             subprocess.Popen(cmd)
 
@@ -844,9 +845,9 @@ class DirSrvTools(object):
     def makeUser(user=DEFAULT_USER, group=DEFAULT_USER, home=DEFAULT_USERHOME):
         try:
             pwd.getpwnam(user)
-            print "OK user %s exists" % user
+            print("OK user %s exists" % user)
         except KeyError:
-            print "Adding user %s" % user
+            print("Adding user %s" % user)
             cmd = [USERADD, '-g', group,
                    '-c', DEFAULT_USER_COMMENT,
                     '-r',
@@ -858,7 +859,7 @@ class DirSrvTools(object):
     @staticmethod
     def lib389User(user=DEFAULT_USER):
         DirSrvTools.makeGroup(group=user)
-        time.sleep(1) # Need a little time for the group to get fully created
+        time.sleep(1)  # Need a little time for the group to get fully created
         DirSrvTools.makeUser(user=user, group=user, home=DEFAULT_USERHOME)
 
     @staticmethod
@@ -909,7 +910,10 @@ class DirSrvTools(object):
                     assert False
         else:
             # Standard prefix lib location
-            libdir = '/lib/dirsrv/'
+            if os.path.isdir('/usr/lib64/dirsrv'):
+                libdir = '/usr/lib64/dirsrv/'
+            else:
+                libdir = '/lib/dirsrv/'
 
         # Gather all the instances so we can adjust the permissions, otherwise
         servers = []
diff --git a/tests/config.py b/tests/config.py
index 8061a9b..6125196 100644
--- a/tests/config.py
+++ b/tests/config.py
@@ -1,4 +1,5 @@
 import logging
+import six
 logging.basicConfig(level=logging.DEBUG)
 log = logging.getLogger(__name__)
 
@@ -34,4 +35,4 @@ def entry_equals(e1, e2):
 
 def dfilter(my_dict, keys):
     """Filter a dict in a 2.4-compatible way"""
-    return dict([(k, v) for k, v in my_dict.iteritems() if k in keys])
+    return dict([(k, v) for k, v in six.iteritems(my_dict) if k in keys])
diff --git a/tests/config_test.py b/tests/config_test.py
index bcec4b3..d60c8f0 100644
--- a/tests/config_test.py
+++ b/tests/config_test.py
@@ -8,18 +8,17 @@
    DirSrv.backend.methodName()
 """
 
-
-import config
-from config import log
-from config import *
+from . import config
+from .config import log
+from .config import *
 
 import lib389
 from lib389 import DirSrv, Entry
 import time
 
 # Test harnesses
-from dsadmin_test import drop_backend, addbackend_harn
-from dsadmin_test import drop_added_entries
+from .dsadmin_test import drop_backend, addbackend_harn
+from .dsadmin_test import drop_added_entries
 
 conn = None
 added_entries = None
@@ -28,6 +27,7 @@ added_backends = None
 MOCK_REPLICA_ID = '12'
 MOCK_TESTREPLICA_DN = "cn=testReplica,cn=ldbm database,cn=plugins,cn=config"
 
+
 def setup():
     # uses an existing 389 instance
     # add a suffix
@@ -40,7 +40,7 @@ def setup():
     conn.added_entries = []
     conn.added_backends = set(['o=mockbe1'])
     conn.added_replicas = []
-    """  
+    """
     # add a backend for testing ruv and agreements
     addbackend_harn(conn, 'testReplica')
 
@@ -48,32 +48,34 @@ def setup():
     addbackend_harn(conn, 'testReplicaCreation')
     """
 
+
 def teardown():
     global conn
     conn.config.loglevel([lib389.LOG_CACHE])
     conn.config.loglevel([256], service='access')
-    
+
     """
     drop_added_entries(conn)
     conn.delete_s(','.join(['cn="o=testreplica"', DN_MAPPING_TREE]))
     drop_backend(conn, 'o=testreplica')
     #conn.delete_s('o=testreplica')
     """
-    
+
+
 def loglevel_test():
     vals = [lib389.LOG_CACHE, lib389.LOG_REPLICA, lib389.LOG_CONNECT]
     expected = sum(vals)
     assert conn.config.loglevel(vals) == expected
-    ret = conn.config.get('nsslapd-errorlog-level') 
+    ret = conn.config.get('nsslapd-errorlog-level')
     assert ret == str(expected), "expected: %r got: %r" % (expected, ret)
-    
+
 
 def loglevel_update_test():
     vals = [lib389.LOG_CACHE, lib389.LOG_CONNECT]
     e = sum(vals)
     assert conn.config.loglevel(vals) == e
     vals = [lib389.LOG_REPLICA]
-    ret = conn.config.loglevel(vals, update=True) 
+    ret = conn.config.loglevel(vals, update=True)
     assert ret == (e + sum(vals)), "expected %s got %s" % (e + sum(vals), ret)
 
 
diff --git a/tests/dsadmin_basic_test.py b/tests/dsadmin_basic_test.py
index 5d57dfb..9eca07b 100644
--- a/tests/dsadmin_basic_test.py
+++ b/tests/dsadmin_basic_test.py
@@ -11,8 +11,8 @@ from ldap import *
 from nose import SkipTest
 from nose.tools import *
 
-import config
-from config import *
+from . import config
+from .config import *
 
 conn = None
 added_entries = None
@@ -24,7 +24,7 @@ def setup():
         conn = DirSrv(**config.auth)
         conn.verbose = True
         conn.added_entries = []
-    except SERVER_DOWN, e:
+    except SERVER_DOWN as e:
         log.error("To run tests you need a working 389 instance %s" % config.auth)
         raise e
 
@@ -44,7 +44,7 @@ def tearDown():
 
 
 def bind_test():
-    print "conn: %s" % conn
+    print ("conn: %s" % conn)
 
 
 def setupBindDN_UID_test():
@@ -109,9 +109,9 @@ def getMTEntry_present_test():
     bename = 'addressbookd16db'
     backendEntry, dummy = conn.backend.add(suffix, benamebase=bename)
     suffixEntry = conn.backend.setup_mt(suffix, bename)
-    
+
     e = conn.getMTEntry(suffix)
-    
+
     conn.backend.delete(bename)
     conn.delete_s(suffixEntry.dn)
     assert e, "Entry should be present %s" % suffix
diff --git a/tests/dsadmin_create_remove_test.py b/tests/dsadmin_create_remove_test.py
index bfa830b..1df0eca 100644
--- a/tests/dsadmin_create_remove_test.py
+++ b/tests/dsadmin_create_remove_test.py
@@ -57,10 +57,10 @@ def default_test():
 #        filename = "%s/slapd-%s/ldif/Example.ldif" % (m1.sroot, m1.inst)
 #        m1.importLDIF(filename, "dc=example,dc=com", None, True)
 #        m1.exportLDIF('/tmp/ldif', "dc=example,dc=com", False, True)
-    print m1.sroot, m1.inst, m1.errlog
+    print (m1.sroot, m1.inst, m1.errlog)
     ent = m1.getEntry(basedn, scope, filt, None)
     if ent:
-        print ent.passwordmaxage
+        print (ent.passwordmaxage)
     instance_config.update({
                            'newinstance': instance_name[1],
                            'newport': port + 10,
@@ -75,15 +75,15 @@ def default_test():
     backendEntry, dummy = m1.backend.add(suffix, bename)
     suffixEntry = m1.backend.setup_mt(suffix, bename)
     cn = backendEntry.getValue('cn')
-    print cn
+    print (cn)
     entry = m1.getEntry(DN_CONFIG, ldap.SCOPE_SUBTREE, "(cn=" + cn + ")")
-    print "new backend entry is:"
-    print entry
-    print entry.getValues('objectclass')
-    print entry.OBJECTCLASS
+    print ("new backend entry is:")
+    print (entry)
+    print (entry.getValues('objectclass'))
+    print (entry.OBJECTCLASS)
     results = m1.search_s("cn=monitor", ldap.SCOPE_SUBTREE)
-    print results
+    print (results)
     results = m1.getBackendsForSuffix("dc=example,dc=com")
-    print results
+    print (results)
 
-    print "done"
+    print ("done")
diff --git a/tests/dsadmin_test.py b/tests/dsadmin_test.py
index 8f28d03..a77dc35 100644
--- a/tests/dsadmin_test.py
+++ b/tests/dsadmin_test.py
@@ -1,9 +1,9 @@
 from nose import *
 from nose.tools import *
 
-import config
-from config import log
-from config import *
+from . import config
+from .config import log
+from .config import *
 
 import ldap
 import time
@@ -33,7 +33,7 @@ def setup():
     conn.added_backends = set(['o=mockbe2'])
     conn.added_replicas = []
     harn_nolog()
-    
+
 def setup_backend():
     global conn
     suffix = 'o=addressbook6'
@@ -48,8 +48,8 @@ def teardown():
     global conn
     conn.rebind()
     drop_added_entries(conn)
-    
-def drop_added_entries(conn):    
+
+def drop_added_entries(conn):
     while conn.added_entries:
         try:
             e = conn.added_entries.pop()
@@ -76,10 +76,10 @@ def drop_added_entries(conn):
 def drop_backend(conn, suffix, bename=None, maxnum=50):
     if not bename:
         bename = [x.dn for x in conn.getBackendsForSuffix(suffix)]
-    
+
     if not bename:
         return None
-        
+
     assert bename, "Missing bename for %r" % suffix
     if not hasattr(bename, '__iter__'):
         bename = [','.join(['cn=%s' % bename, lib389.DN_LDBM])]
@@ -126,7 +126,7 @@ def addbackend_harn(conn, name, beattrs=None):
 
     conn.add(e)
     conn.added_entries.append(e.dn)
-    
+
     return ret
 
 
@@ -168,13 +168,13 @@ def addreplica_write_test():
         'id': 124
     }
     replica.update(user)
-    
+
     #create backend and suffix
     backendEntry, dummy = conn.backend.add(suffix, benamebase=backend)
     suffixEntry = conn.backend.setup_mt(suffix, backend)
 
     ret = conn.replicaSetupAll(replica)
-    
+
     assert ret != -1, "Error in setup replica: %s" % ret
 
 
diff --git a/tests/entry_test.py b/tests/entry_test.py
index 705b7f6..b8e0b7b 100644
--- a/tests/entry_test.py
+++ b/tests/entry_test.py
@@ -82,6 +82,6 @@ class TestEntry(object):
             'nsds5replicabinddn': binddnlist,
             'nsds5replicalegacyconsumer': legacy
         })
-        uentry_s, entry_s = map(str, (uentry, entry))
+        uentry_s, entry_s = list(map(str, (uentry, entry)))
         assert uentry_s == entry_s, "Mismatching entries [%r] vs [%r]" % (
             uentry, entry)
diff --git a/tests/mappingTree_test.py b/tests/mappingTree_test.py
index 6780ee5..de75551 100644
--- a/tests/mappingTree_test.py
+++ b/tests/mappingTree_test.py
@@ -29,6 +29,7 @@ NEW_BACKEND_2      = 'test_bis_createdb'
 NEW_CHILDSUFFIX_2  = 'o=child2,o=test_bis_create'
 NEW_CHILDBACKEND_2 = 'test_bis_createchilddb'
 
+
 class Test_mappingTree():
     def _add_user(self, success=True):
         try:
@@ -42,7 +43,7 @@ class Test_mappingTree():
             else:
                 self.instance.log.info('Fail to add (expected): %s' % e.args)
                 return
-            
+
         self.instance.log.info('%s added' % TEST_REPL_DN)
 
     def _mod_user(self, success=True):
@@ -55,7 +56,7 @@ class Test_mappingTree():
             else:
                 self.instance.log.info('Fail to modify (expected): %s' % e.args)
                 return
-            
+
         self.instance.log.info('%s modified' % TEST_REPL_DN)
 
     def setUp(self):
@@ -73,7 +74,6 @@ class Test_mappingTree():
         instance.open()
         self.instance = instance
 
-
     def tearDown(self):
         if self.instance.exists():
             self.instance.delete()
@@ -85,28 +85,28 @@ class Test_mappingTree():
         ents = self.instance.mappingtree.list()
         for ent in ents:
                 self.instance.log.info('test_list: %r' % ent)
-                
+
         # get with a dedicated suffix
         ents = self.instance.mappingtree.list(suffix=DEFAULT_SUFFIX)
         assert len(ents) == 1
         self.instance.log.info('test_list(suffix): %r' % ent)
-        
+
         ents = self.instance.mappingtree.list(suffix="dc=dummy")
         assert len(ents) == 0
-        
+
         # get with a dedicated backend name
         ents = self.instance.mappingtree.list(bename=DEFAULT_BENAME)
         assert len(ents) == 1
         self.instance.log.info('test_list(bename): %r' % ent)
-        
+
         ents = self.instance.mappingtree.list(bename="dummy")
         assert len(ents) == 0
-        
+
         # check backend is taken first
         ents = self.instance.mappingtree.list(suffix="dc=dummy", bename=DEFAULT_BENAME)
         assert len(ents) == 1
         self.instance.log.info('test_list(suffix, bename): %r' % ent)
-        
+
     def test_create(self):
         '''
             This test will create 2 backends/mapping trees, then 2 childs backend/mapping tree
@@ -115,55 +115,54 @@ class Test_mappingTree():
         # before creating mapping trees, the backends must exists
         backendEntry = self.instance.backend.create(NEW_SUFFIX_1, {BACKEND_NAME: NEW_BACKEND_1})
         backendEntry = self.instance.backend.create(NEW_SUFFIX_2, {BACKEND_NAME: NEW_BACKEND_2})
-        
+
         ents = self.instance.mappingtree.list()
         nb_mappingtree = len(ents)
-        
+
         # create a first additional mapping tree
         self.instance.mappingtree.create(NEW_SUFFIX_1, bename=NEW_BACKEND_1)
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree + 1)
-        
+
         # create a second additional mapping tree
         self.instance.mappingtree.create(NEW_SUFFIX_2, bename=NEW_BACKEND_2)
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree + 2)
-        
+
         # Creating a mapping tree that already exists => it just returns the existing MT
         self.instance.mappingtree.create(NEW_SUFFIX_1, bename=NEW_BACKEND_1)
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree + 2)
-        
+
          # Creating a mapping tree that already exists => it just returns the existing MT
         self.instance.mappingtree.create(NEW_SUFFIX_2, bename=NEW_BACKEND_2)
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree + 2)
-        
+
         # before creating mapping trees, the backends must exists
         backendEntry = self.instance.backend.create(NEW_CHILDSUFFIX_1, {BACKEND_NAME: NEW_CHILDBACKEND_1})
         backendEntry = self.instance.backend.create(NEW_CHILDSUFFIX_2, {BACKEND_NAME: NEW_CHILDBACKEND_2})
-        
+
         # create a third additional mapping tree, that is child of NEW_SUFFIX_1
         self.instance.mappingtree.create(NEW_CHILDSUFFIX_1, bename=NEW_CHILDBACKEND_1, parent=NEW_SUFFIX_1)
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree + 3)
-        
+
         ents = self.instance.mappingtree.list(suffix=NEW_CHILDSUFFIX_1)
         assert len(ents) == 1
         ent = ents[0]
         assert ent.hasAttr(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX]) and (ent.getValue(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX]) == NEW_SUFFIX_1)
-        
+
         # create a fourth additional mapping tree, that is child of NEW_SUFFIX_2
         self.instance.mappingtree.create(NEW_CHILDSUFFIX_2, bename=NEW_CHILDBACKEND_2, parent=NEW_SUFFIX_2)
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree + 4)
-        
+
         ents = self.instance.mappingtree.list(suffix=NEW_CHILDSUFFIX_2)
         assert len(ents) == 1
         ent = ents[0]
         assert ent.hasAttr(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX]) and (ent.getValue(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX]) == NEW_SUFFIX_2)
-        
-        
+
     def test_delete(self):
         '''
             Delete the mapping tree and check the remaining number.
@@ -172,70 +171,70 @@ class Test_mappingTree():
         ents = self.instance.mappingtree.list()
         nb_mappingtree = len(ents)
         deleted = 0
-        
+
         self.instance.log.debug("delete MT for suffix " + NEW_CHILDSUFFIX_1)
         self.instance.mappingtree.delete(suffix=NEW_CHILDSUFFIX_1)
         deleted += 1
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree - deleted)
-        
+
         self.instance.log.debug("delete MT with backend " + NEW_CHILDBACKEND_2)
         self.instance.mappingtree.delete(bename=NEW_CHILDBACKEND_2)
         deleted += 1
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree - deleted)
-        
+
         self.instance.log.debug("delete MT for suffix %s and with backend %s" % (NEW_SUFFIX_1, NEW_BACKEND_1))
         self.instance.mappingtree.delete(suffix=NEW_SUFFIX_1,bename=NEW_BACKEND_1)
         deleted += 1
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree - deleted)
-        
+
 
         ents = self.instance.mappingtree.list(suffix=NEW_SUFFIX_2)
         assert len(ents) == 1
         self.instance.log.debug("delete MT with DN %s (dummy suffix/backend)" % (ents[0].dn))
         self.instance.mappingtree.delete(suffix="o=dummy", bename="foo", name=ents[0].dn)
-        
+
     def test_getProperties(self):
         ents = self.instance.mappingtree.list()
         nb_mappingtree = len(ents)
-        
+
         # create a first additional mapping tree
         self.instance.mappingtree.create(NEW_SUFFIX_1, bename=NEW_BACKEND_1)
         ents = self.instance.mappingtree.list()
         assert len(ents) == (nb_mappingtree + 1)
-        
+
         # check we can get properties from suffix
         prop_ref = self.instance.mappingtree.getProperties(suffix=NEW_SUFFIX_1)
         self.instance.log.info("properties [suffix] %s: %r" % (NEW_SUFFIX_1, prop_ref))
-        
+
         # check we can get properties from backend name
         properties = self.instance.mappingtree.getProperties(bename=NEW_BACKEND_1)
-        for key in properties.keys():
+        for key in list(properties.keys()):
             assert prop_ref[key] == properties[key]
         self.instance.log.info("properties [backend] %s: %r" % (NEW_SUFFIX_1, properties))
-        
+
         # check we can get properties from suffix AND backend name
         properties = self.instance.mappingtree.getProperties(suffix=NEW_SUFFIX_1, bename=NEW_BACKEND_1)
-        for key in properties.keys():
+        for key in list(properties.keys()):
             assert prop_ref[key] == properties[key]
         self.instance.log.info("properties [suffix+backend]%s: %r" % (NEW_SUFFIX_1, properties))
-        
+
         # check we can get properties from MT entry
         ents = self.instance.mappingtree.list(suffix=NEW_SUFFIX_1)
         assert len(ents) == 1
         ent = ents[0]
         properties = self.instance.mappingtree.getProperties(name=ent.dn)
-        for key in properties.keys():
+        for key in list(properties.keys()):
             assert prop_ref[key] == properties[key]
         self.instance.log.info("properties [MT entry DN] %s: %r" % (NEW_SUFFIX_1, properties))
-        
+
         # check we can get only one properties
         properties = self.instance.mappingtree.getProperties(name=ent.dn,properties=[MT_STATE])
         assert len(properties) == 1
         assert properties[MT_STATE] == prop_ref[MT_STATE]
-        
+
         try:
             properties = self.instance.mappingtree.getProperties(name=ent.dn,properties=['dummy'])
             assert 0  # it should return an exception
@@ -243,33 +242,33 @@ class Test_mappingTree():
             pass
         except KeyError:
             pass
-        
+
     def toSuffix(self):
         ents = self.instance.mappingtree.list()
         suffix = self.instance.mappingtree.toSuffix(entry=ents[0])
         assert len(suffix) > 0
         self.instance.log.info("suffix (entry) is %s" % suffix[0])
-        
+
         suffix = self.instance.mappingtree.toSuffix(name=ents[0].dn)
         assert len(suffix) > 0
         self.instance.log.info("suffix (dn) is %s" % suffix[0])
-        
+
         try:
             suffix = self.instance.mappingtree.toSuffix()
         except InvalidArgumentError:
             pass
-        
+
 if __name__ == "__main__":
     #import sys;sys.argv = ['', 'Test.testName']
     test = Test_mappingTree()
     test.setUp()
-    
+
     test.test_list()
     test.test_create()
     test.test_delete()
     test.test_getProperties()
     test.toSuffix()
-    
+
     test.tearDown()
 
 
-- 
1.9.3

