diff --git a/clone.py b/clone.py
index 7d019637..21dba549 100755
--- a/clone.py
+++ b/clone.py
@@ -76,7 +76,7 @@ If set to '' (empty string), it defaults to '%s'""" % (DEFAULT_MP_CONF_URL))
         else:
             repo.clone(version, options.fallback_branch, options.with_optionals, options.marketplace_conf)
     #pylint: disable=C0103
-    except ExitException, e:
+    except ExitException as e:
         if e.message is not None:
             log("[ERROR] %s" % e.message, sys.stderr)
         sys.exit(e.return_code)
diff --git a/scripts/fixeclipse.py b/scripts/fixeclipse.py
index f6380726..c4f8262c 100755
--- a/scripts/fixeclipse.py
+++ b/scripts/fixeclipse.py
@@ -55,11 +55,11 @@ def read_file_content(filename):
     try:
         f = open(filename, "rb")
         content = f.read()
-    except IOError, e:
+    except IOError as e:
         msg = "Cannot read file content from " + filename
         if e.message is not None:
             msg = msg + ": " + e.message
-        print msg
+        print(msg)
         raise
     finally:
         f.close()
@@ -75,11 +75,11 @@ def write_file_content(filename, content):
     try:
         f = open(filename, "wb")
         f.write(content)
-    except IOError, e:
+    except IOError as e:
         msg = "Cannot write file content to " + filename
         if e.message is not None:
             msg = msg + ": " + e.message
-        print msg
+        print(msg)
         raise
     finally:
         f.close()
@@ -101,7 +101,7 @@ def find_files_by_pattern(pattern):
 
 def fix_classpath():
     """Fixes .classpath files"""
-    print "Fixing Eclipse classpath to use bin instead of target directory..."
+    print("Fixing Eclipse classpath to use bin instead of target directory...")
 
     test_pattern = get_test_pattern()
     main_pattern = get_main_pattern()
@@ -122,17 +122,17 @@ def fix_classpath():
             # Content has been changed
             if changed:
                 write_file_content(cpfile, content[0])
-                print cpfile
+                print(cpfile)
 
         except IOError:
-            print "Cannot process file " + cpfile
+            print(("Cannot process file " + cpfile))
 
-    print "Done."
+    print("Done.")
 
 
 def replace_files():
     """Replaces missing or badly generated files"""
-    print "Replacing missing or badly generated files with .*.ok files..."
+    print("Replacing missing or badly generated files with .*.ok files...")
 
     try:
         # Redirect diff output to null device.
@@ -152,12 +152,12 @@ def replace_files():
             if 0 != call(cmd, stdout=nulldevice, stderr=nulldevice,
                          shell=False):
                 copy(okfile, newfile)
-                print newfile
+                print(newfile)
 
     finally:
         nulldevice.close()
 
-    print "Done."
+    print("Done.")
 
 if __name__ == '__main__':
     OLD_MAIN = "target/classes"
diff --git a/scripts/generate-licenses.py b/scripts/generate-licenses.py
index 6dea0262..5b962eb8 100755
--- a/scripts/generate-licenses.py
+++ b/scripts/generate-licenses.py
@@ -79,7 +79,7 @@ def parse_licenses(filename):
             # (AL 1.1) (BSD 4) (Public Domain) MXP1: Xml Pull Parser 3rd Edition (XPP3) (xpp3:xpp3:1.1.4c - http://www.extreme.indiana.edu/xgws/xsoap/xpp/mxp1/)
             m = re.match('((\([^)]+\) )+)(.+) \(([^ :]+):([^ :]+):([^ :]+) - .+\)', line)
             if m is None:
-                print('NXP-25776 cannot parse: ', line)
+                print(('NXP-25776 cannot parse: ', line))
                 continue
             license_list = [l.strip('() ') for l in m.group(1).split(') (')]
             name = m.group(3)
@@ -95,12 +95,12 @@ def parse_licenses(filename):
     return licenses, versions
 
 def fix_unknown(licenses, add_licenses, versions, add_versions):
-    for ga, license_list in licenses.iteritems():
+    for ga, license_list in list(licenses.items()):
         if license_list == ['Unknown license']:
             if ga in add_licenses:
                 licenses[ga] = add_licenses[ga]
             else:
-                print('XXX unknown', ga)
+                print(('XXX unknown', ga))
     for ga in add_licenses:
         if ga not in licenses:
             licenses[ga] = add_licenses[ga]
@@ -179,7 +179,7 @@ def dump(licenses, versions, descriptions, gas, whitelist):
     whites = []
     blacks = []
 
-    for ga, galist in licenses.iteritems():
+    for ga, galist in list(licenses.items()):
         if ga in gas:
             gas.remove(ga)
             out = blacks
diff --git a/scripts/nxutils.py b/scripts/nxutils.py
index 795a8cef..493132f7 100644
--- a/scripts/nxutils.py
+++ b/scripts/nxutils.py
@@ -17,7 +17,7 @@ Contributors:
 
 Utilities for Python scripts."""
 
-import ConfigParser
+import configparser
 import errno
 import os
 import platform
@@ -27,7 +27,7 @@ import shutil
 import subprocess
 import sys
 import time
-import urllib2
+import urllib.request, urllib.error, urllib.parse
 from zipfile import ZIP_DEFLATED, ZipFile
 from distutils.version import LooseVersion
 import warnings
@@ -289,15 +289,15 @@ class Repository(object):
         defaults = {'other_versions': None, 'prepared': 'False', 'performed': 'False', 'branched': 'False',
                     "profiles": '', "auto_increment_policy": "auto_patch"}
         defaults.update(user_defaults)
-        mp_config = ConfigParser.SafeConfigParser(defaults=defaults)
+        mp_config = configparser.SafeConfigParser(defaults=defaults)
         if marketplace_conf is None:
             no_remote = True
         else:
             try:
-                mp_config.readfp(urllib2.urlopen(marketplace_conf))
+                mp_config.readfp(urllib.request.urlopen(marketplace_conf))
                 log("Read configuration from: '%s'" % marketplace_conf)
                 no_remote = False
-            except urllib2.URLError:
+            except urllib.error.URLError:
                 no_remote = True
             except ValueError:
                 no_remote = True
@@ -411,7 +411,7 @@ def check_output(cmd):
         p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                              shell=platform.system() == "Windows")
     # pylint: disable=C0103
-    except OSError, e:
+    except OSError as e:
         log("$> " + cmd)
         if e.errno == errno.ENOENT:
             raise ExitException(1, "Command not found: '%s'" % args[0])
@@ -424,7 +424,7 @@ def check_output(cmd):
         if err is None or err == "":
             err = out
         raise ExitException(retcode, "Command '%s' returned non-zero exit code (%s)\n%s" % (cmd, retcode, err))
-    return out.strip()
+    return out.strip().decode("utf8")
 
 
 # pylint: disable=R0912,R0913
@@ -453,14 +453,14 @@ def system(cmd, failonerror=True, delay_stdout=True, logOutput=True, wait=True,
             if wait:
                 out, err = p.communicate()
                 if logOutput:
-                    sys.stdout.write(out)
+                    sys.stdout.write(out.decode("utf8"))
                     sys.stdout.flush()
         else:
             logOutput = True
             p = subprocess.Popen(args, shell=platform.system() == "Windows")
             if wait:
                 p.wait()
-    except OSError, e:
+    except OSError as e:
         if e.errno == errno.ENOENT:
             raise ExitException(1, "Command not found: '%s'" % args[0])
         else:
@@ -535,13 +535,13 @@ def assert_git_config():
         raise ExitException(1, "Requires Git version %s+ (detected %s)" % (REQUIRED_GIT_VERSION, t))
     try:
         t = check_output("git config --get-all color.branch")
-    except ExitException, e:
+    except ExitException as e:
         # Error code 1 is fine (default value)
         if e.return_code > 1:
             log("[WARN] %s" % e.message, sys.stderr)
     try:
         t += check_output("git config --get-all color.status")
-    except ExitException, e:
+    except ExitException as e:
         # Error code 1 is fine (default value)
         if e.return_code > 1:
             log("[WARN] %s" % e.message, sys.stderr)
diff --git a/scripts/release.py b/scripts/release.py
index b6f15de9..037813ba 100755
--- a/scripts/release.py
+++ b/scripts/release.py
@@ -64,10 +64,10 @@ import shutil
 import sys
 import tempfile
 from lxml import etree
-from IndentedHelpFormatterWithNL import IndentedHelpFormatterWithNL
-from nxutils import ExitException, Repository, assert_git_config, extract_zip, \
+from .IndentedHelpFormatterWithNL import IndentedHelpFormatterWithNL
+from .nxutils import ExitException, Repository, assert_git_config, extract_zip, \
     log, make_zip, system
-from terminalsize import get_terminal_size
+from .terminalsize import get_terminal_size
 
 
 PKG_RENAMINGS = {
@@ -205,10 +205,10 @@ class Release(object):
     # pylint: disable=R0913
     def __init__(self, repo, release_info):
         if release_info.dryrun:
-            print "DEBUG -- init Release with:"
-            for key, value in vars(release_info).iteritems():
-                print "DEBUG: %s=%s" % (key, value)
-            print
+            print("DEBUG -- init Release with:")
+            for key, value in vars(release_info).items():
+                print("DEBUG: %s=%s" % (key, value))
+            print()
 
         self.repo = repo
         self.params = release_info
@@ -241,10 +241,10 @@ class Release(object):
             log("Working on custom repository...")
 
         if release_info.dryrun:
-            print "\nDEBUG -- Release initialized with:"
-            for key, value in vars(self).iteritems():
-                print "DEBUG: %s=%s" % (key, value)
-            print
+            print("\nDEBUG -- Release initialized with:")
+            for key, value in vars(self).items():
+                print("DEBUG: %s=%s" % (key, value))
+            print()
 
     def set_other_versions_and_patterns(self, release_info):
         """Set other versions and replacement patterns"""
@@ -266,12 +266,12 @@ class Release(object):
                     custom_files_pattern = other_versions_split[0]
                     try:
                         re.compile(custom_files_pattern)
-                    except re.error, e:
+                    except re.error as e:
                         raise ExitException(1, "Bad pattern: '%s'\n%s" % (custom_files_pattern, e.message))
                 if other_versions_split[1]:
                     try:
                         re.compile(other_versions_split[1])
-                    except re.error, e:
+                    except re.error as e:
                         raise ExitException(1, message = "Bad pattern: '%s'\n%s" % (other_versions_split[1], e.message))
                     custom_props_pattern = "{%s}%s" % (NAMESPACES.get("pom"), other_versions_split[1])
                 other_versions = other_versions_split[2]
@@ -538,13 +538,13 @@ class Release(object):
             version = self.tag
 
         # Default packages
-        for old, new in PKG_RENAMINGS.items():
+        for old, new in list(PKG_RENAMINGS.items()):
             self.package(old % version, new % version)
         # Tomcat SDK packages
-        for old, new in PKG_RENAMINGS_OPTIONALS.items():
+        for old, new in list(PKG_RENAMINGS_OPTIONALS.items()):
             self.package(old % version, new % version, False)
         # MP
-        for old, new in PKG_MP.items():
+        for old, new in list(PKG_MP.items()):
             self.package_mp(old % version, new % version, False)
 
         self.package_sources(version)
@@ -581,7 +581,7 @@ class Release(object):
         for filename in (fnmatch.filter(files, "*ctl") +
                          fnmatch.filter(files, "*.sh") +
                          fnmatch.filter(files, "*.command")):
-            os.chmod(os.path.join(new_name, "bin", filename), 0744)
+            os.chmod(os.path.join(new_name, "bin", filename), 0o744)
         with open(os.path.join(new_name, "bin", "nuxeo.conf"), "a") as f:
             f.write("nuxeo.wizard.done=false\n")
         make_zip(os.path.join(
@@ -1088,7 +1088,7 @@ Available options:\n
             release.test()
         else:
             raise ExitException(1, "Unknown command! See usage with '-h'.")
-    except ExitException, e:
+    except ExitException as e:
         if e.message is not None:
             log("[ERROR] %s" % e.message, sys.stderr)
         sys.exit(e.return_code)
diff --git a/scripts/release_mp.py b/scripts/release_mp.py
index 80ddc1ff..520cff58 100755
--- a/scripts/release_mp.py
+++ b/scripts/release_mp.py
@@ -26,10 +26,10 @@ import os
 import sys
 import traceback
 
-from IndentedHelpFormatterWithNL import IndentedHelpFormatterWithNL
-from nxutils import ExitException, Repository, assert_git_config, log, system, DEFAULT_MP_CONF_URL
-from release import Release, ReleaseInfo
-from terminalsize import get_terminal_size
+from .IndentedHelpFormatterWithNL import IndentedHelpFormatterWithNL
+from .nxutils import ExitException, Repository, assert_git_config, log, system, DEFAULT_MP_CONF_URL
+from .release import Release, ReleaseInfo
+from .terminalsize import get_terminal_size
 
 
 CONNECT_TEST_URL = "https://nos-preprod-connect.nuxeocloud.com/nuxeo"
@@ -65,7 +65,7 @@ class ReleaseMP(object):
             default_info = ReleaseInfo()
             default_info.read_release_log(default_conf)
             prefix = default_info.module
-            for key, value in vars(default_info).iteritems():
+            for key, value in vars(default_info).items():
                 self.defaults[prefix + "-" + key] = str(value)
         self.mp_config = self.repo.get_mp_config(self.marketplace_conf, self.defaults)
 
@@ -136,17 +136,17 @@ class ReleaseMP(object):
                 release_log = mp_release.log_summary()
                 release_info.read_release_log(release_log)
                 if dryrun:
-                    print "DEBUG -- init %s with:" % marketplace
-                for key, value in vars(release_info).iteritems():
+                    print("DEBUG -- init %s with:" % marketplace)
+                for key, value in vars(release_info).items():
                     if dryrun:
-                        print "DEBUG: %s-%s=%s" % (marketplace, key, value)
+                        print("DEBUG: %s-%s=%s" % (marketplace, key, value))
                     self.mp_config.set("DEFAULT", marketplace + "-" + key, str(value))
                 if dryrun:
-                    print
+                    print()
 
                 mp_release.prepare(dryrun=dryrun, upgrade_only=upgrade_only, dodeploy=True)
                 prepared = True
-            except Exception, e:
+            except Exception as e:
                 stack = traceback.format_exc()
                 if hasattr(e, 'message') and e.message is not None:
                     stack = e.message + "\n" + stack
@@ -214,19 +214,19 @@ class ReleaseMP(object):
                 release_log = mp_release.log_summary()
                 release_info.read_release_log(release_log)
                 if dryrun:
-                    print "DEBUG -- init %s with:" % marketplace
-                for key, value in vars(release_info).iteritems():
+                    print("DEBUG -- init %s with:" % marketplace)
+                for key, value in vars(release_info).items():
                     if dryrun:
-                        print "DEBUG: %s-%s=%s" % (marketplace, key, value)
+                        print("DEBUG: %s-%s=%s" % (marketplace, key, value))
                     self.mp_config.set("DEFAULT", marketplace + "-" + key, str(value))
                 if dryrun:
-                    print
+                    print()
 
                 mp_release.release_branch(dryrun=dryrun, upgrade_only=upgrade_only)
                 self.mp_config.set(marketplace, "next_snapshot", "done")
                 self.mp_config.set(marketplace, "branch", mp_release.maintenance_branch)
                 branched = True
-            except Exception, e:
+            except Exception as e:
                 stack = traceback.format_exc()
                 if hasattr(e, 'message') and e.message is not None:
                     stack = e.message + "\n" + stack
@@ -271,7 +271,7 @@ class ReleaseMP(object):
                 mp_release = Release(mp_repo, release_info)
                 mp_release.perform(dryrun=dryrun, upgrade_only=upgrade_only)
                 performed = True
-            except Exception, e:
+            except Exception as e:
                 stack = traceback.format_exc()
                 if hasattr(e, 'message') and e.message is not None:
                     stack = e.message + "\n" + stack
@@ -385,7 +385,7 @@ This is the id of the connect client document on Connect. Sample value: 45a78af-
             full_release.test()
         else:
             raise ExitException(1, "Unknown command! See usage with '-h'.")
-    except ExitException, e:
+    except ExitException as e:
         if e.message is not None:
             log("[ERROR] %s" % e.message, sys.stderr)
         sys.exit(e.return_code)
diff --git a/scripts/terminalsize.py b/scripts/terminalsize.py
index 319c5a27..7680c979 100644
--- a/scripts/terminalsize.py
+++ b/scripts/terminalsize.py
@@ -104,7 +104,7 @@ def _get_terminal_size_linux():
 
 
 def main():
-    print  '(width, height) = ', get_terminal_size()
+    print('(width, height) = ', get_terminal_size())
 
 if __name__ == "__main__":
     main()
