Sophie

Sophie

distrib > Mageia > 9 > aarch64 > media > core-release-src > by-pkgid > a772240b0baa723a1068ca680334e68f > files > 3

funkload-1.17.1-8.mga9.src.rpm

From d7f20bf3d59f0f6fe64868cd7ff7aa0512e35cb8 Mon Sep 17 00:00:00 2001
From: Ed Schofield <ed@pythoncharmers.com>
Date: Tue, 18 Aug 2015 21:45:19 +1000
Subject: [PATCH] Initial Py2/3 patches (futurize --stage1 .)

---
 .../FunkloadMunin/MonitorPluginMunin.py       |  8 ++--
 ez_setup.py                                   | 21 ++++----
 src/funkload/BenchRunner.py                   |  9 ++--
 src/funkload/CredentialFile.py                |  9 ++--
 src/funkload/CredentialRandom.py              |  7 +--
 src/funkload/DemoInstaller.py                 |  5 +-
 src/funkload/Distributed.py                   | 18 +++----
 src/funkload/FunkLoadDocTest.py               |  5 +-
 src/funkload/FunkLoadHTTPServer.py            |  3 +-
 src/funkload/FunkLoadTestCase.py              | 18 +++----
 src/funkload/Lipsum.py                        | 43 +++++++++--------
 src/funkload/MergeResultFiles.py              | 24 +++++-----
 src/funkload/Monitor.py                       |  9 ++--
 src/funkload/MonitorPlugins.py                |  2 +-
 src/funkload/MonitorPluginsDefault.py         |  3 +-
 src/funkload/PatchWebunit.py                  | 20 ++++----
 src/funkload/Recorder.py                      | 12 +++--
 src/funkload/ReportBuilder.py                 | 48 ++++++++++---------
 src/funkload/ReportRenderDiff.py              | 12 +++--
 src/funkload/ReportRenderHtml.py              |  7 +--
 src/funkload/ReportRenderHtmlBase.py          | 10 ++--
 src/funkload/ReportRenderHtmlGnuPlot.py       | 24 +++++-----
 src/funkload/ReportRenderOrg.py               |  9 ++--
 src/funkload/ReportRenderRst.py               | 25 +++++-----
 src/funkload/ReportRenderTrend.py             | 18 +++----
 src/funkload/ReportStats.py                   |  3 +-
 src/funkload/TestRunner.py                    | 25 +++++-----
 src/funkload/XmlRpcBase.py                    |  5 +-
 .../django_demo/django_test_server/manage.py  |  3 +-
 .../django_test_server/methods/urls.py        |  3 +-
 src/funkload/rtfeedback.py                    | 11 +++--
 src/funkload/tests/test_Install.py            |  5 +-
 src/funkload/utils.py                         | 10 ++--
 33 files changed, 237 insertions(+), 197 deletions(-)

diff --git a/contrib/FunkloadMunin/FunkloadMunin/MonitorPluginMunin.py b/contrib/FunkloadMunin/FunkloadMunin/MonitorPluginMunin.py
index 3d04344..d941af1 100644
--- a/contrib/FunkloadMunin/FunkloadMunin/MonitorPluginMunin.py
+++ b/contrib/FunkloadMunin/FunkloadMunin/MonitorPluginMunin.py
@@ -88,15 +88,15 @@ def _getConfig(self, name, cmd, env):
             count=False
             data_name=self._nameResult(name, field)
 
-            if output_parsed.has_key("%s.label"%field):
+            if "%s.label"%field in output_parsed:
                 label=output_parsed["%s.label"%field]
 #            if output_parsed.has_key("%s.info"%field):
 #                label=output_parsed["%s.info"%field]
             
-            if output_parsed.has_key("%s.negative"%field):
+            if "%s.negative"%field in output_parsed:
                 neg=self._nameResult(name, output_parsed["%s.negative"%field])
 
-            if output_parsed.has_key("%s.type"%field):
+            if "%s.type"%field in output_parsed:
                 t=output_parsed["%s.type"%field]
                 if t=='COUNTER' or t=='DERIVE':
                     count=True
@@ -104,7 +104,7 @@ def _getConfig(self, name, cmd, env):
             ret.append((data_name, label, neg, count))
 
         title=None
-        if output_parsed.has_key('graph_vlabel'):
+        if 'graph_vlabel' in output_parsed:
             title=output_parsed['graph_vlabel']
             
         return [title, ret]
diff --git a/ez_setup.py b/ez_setup.py
index b74adc0..ec724f7 100644
--- a/ez_setup.py
+++ b/ez_setup.py
@@ -13,6 +13,7 @@
 
 This file can also be run as a script to install or upgrade setuptools.
 """
+from __future__ import print_function
 import sys
 DEFAULT_VERSION = "0.6c11"
 DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
@@ -70,10 +71,10 @@ def _validate_md5(egg_name, data):
     if egg_name in md5_data:
         digest = md5(data).hexdigest()
         if digest != md5_data[egg_name]:
-            print >>sys.stderr, (
+            print((
                 "md5 validation of %s failed!  (Possible download problem?)"
                 % egg_name
-            )
+            ), file=sys.stderr)
             sys.exit(2)
     return data
 
@@ -103,14 +104,14 @@ def do_download():
         return do_download()       
     try:
         pkg_resources.require("setuptools>="+version); return
-    except pkg_resources.VersionConflict, e:
+    except pkg_resources.VersionConflict as e:
         if was_imported:
-            print >>sys.stderr, (
+            print((
             "The required version of setuptools (>=%s) is not available, and\n"
             "can't be installed while this script is running. Please install\n"
             " a more recent version first, using 'easy_install -U setuptools'."
             "\n\n(Currently using %r)"
-            ) % (version, e.args[0])
+            ) % (version, e.args[0]), file=sys.stderr)
             sys.exit(2)
     except pkg_resources.DistributionNotFound:
         pass
@@ -216,10 +217,10 @@ def main(argv, version=DEFAULT_VERSION):
                 os.unlink(egg)
     else:
         if setuptools.__version__ == '0.0.1':
-            print >>sys.stderr, (
+            print((
             "You have an obsolete version of setuptools installed.  Please\n"
             "remove it from your system entirely before rerunning this script."
-            )
+            ), file=sys.stderr)
             sys.exit(2)
 
     req = "setuptools>="+version
@@ -238,8 +239,8 @@ def main(argv, version=DEFAULT_VERSION):
             from setuptools.command.easy_install import main
             main(argv)
         else:
-            print "Setuptools version",version,"or greater has been installed."
-            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+            print("Setuptools version",version,"or greater has been installed.")
+            print('(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)')
 
 def update_md5(filenames):
     """Update our built-in md5 registry"""
@@ -262,7 +263,7 @@ def update_md5(filenames):
 
     match = re.search("\nmd5_data = {\n([^}]+)}", src)
     if not match:
-        print >>sys.stderr, "Internal error!"
+        print("Internal error!", file=sys.stderr)
         sys.exit(2)
 
     src = src[:match.start(1)] + repl + src[match.end(1):]
diff --git a/src/funkload/BenchRunner.py b/src/funkload/BenchRunner.py
index 0074d62..a4c1818 100644
--- a/src/funkload/BenchRunner.py
+++ b/src/funkload/BenchRunner.py
@@ -23,6 +23,7 @@
 
 $Id: BenchRunner.py 24746 2005-08-31 09:59:27Z bdelbosc $
 """
+from __future__ import absolute_import
 import os
 import platform
 import sys
@@ -37,9 +38,9 @@
 from xmlrpclib import ServerProxy, Fault
 import signal
 
-from FunkLoadTestCase import FunkLoadTestCase
-from FunkLoadHTTPServer import FunkLoadHTTPServer
-from utils import mmn_encode, set_recording_flag, recording, thread_sleep, \
+from .FunkLoadTestCase import FunkLoadTestCase
+from .FunkLoadHTTPServer import FunkLoadHTTPServer
+from .utils import mmn_encode, set_recording_flag, recording, thread_sleep, \
                   trace, red_str, green_str, get_version
 try:
     from funkload.rtfeedback import (FeedbackSender, DEFAULT_ENDPOINT,
@@ -884,7 +885,7 @@ def run_distributed(options, module_name, class_name, method_name, sys_args):
         distmgr = DistributionMgr(
             module_name, class_name, method_name, options, sys_args)
         _manager = distmgr
-    except UserWarning, error:
+    except UserWarning as error:
         trace(red_str("Distribution failed with:%s \n" % (error)))
         return 1
     
diff --git a/src/funkload/CredentialFile.py b/src/funkload/CredentialFile.py
index 2bbad0f..df9c29f 100644
--- a/src/funkload/CredentialFile.py
+++ b/src/funkload/CredentialFile.py
@@ -19,11 +19,12 @@
 
 $Id$
 """
+from __future__ import absolute_import
 import sys
 from ConfigParser import NoOptionError
 
-from XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController
-from CredentialBase import CredentialBaseServer
+from .XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController
+from .CredentialBase import CredentialBaseServer
 
 
 # ------------------------------------------------------------
@@ -132,7 +133,7 @@ def _loadGroups(self, file_path):
             for user in users:
                 if self.lofc and len(group) >= self.lofc:
                     break
-                if self._passwords.has_key(user):
+                if user in self._passwords:
                     group.add(user)
                 else:
                     self.logd('Missing password for %s in group %s' % (user,
@@ -144,7 +145,7 @@ def getCredential(self, group=None):
 
         Credential are taken incrementally in a loop.
         """
-        user = self._groups[group].next()
+        user = next(self._groups[group])
         password = self._passwords[user]
         self.logd("getCredential(%s) return (%s, %s)" % (
             group, user, password))
diff --git a/src/funkload/CredentialRandom.py b/src/funkload/CredentialRandom.py
index 7f18064..f7751ba 100644
--- a/src/funkload/CredentialRandom.py
+++ b/src/funkload/CredentialRandom.py
@@ -19,11 +19,12 @@
 
 $Id$
 """
+from __future__ import absolute_import
 import sys
 
-from Lipsum import Lipsum
-from XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController
-from CredentialBase import CredentialBaseServer
+from .Lipsum import Lipsum
+from .XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController
+from .CredentialBase import CredentialBaseServer
 
 # ------------------------------------------------------------
 # Server
diff --git a/src/funkload/DemoInstaller.py b/src/funkload/DemoInstaller.py
index 7e2fbcb..ef131c8 100644
--- a/src/funkload/DemoInstaller.py
+++ b/src/funkload/DemoInstaller.py
@@ -1,4 +1,5 @@
 """Extract the demo from the funkload egg into the current path."""
+from __future__ import print_function
 
 import os
 from shutil import copytree
@@ -7,12 +8,12 @@
 def main():
     """main."""
     demo_path = 'funkload-demo'
-    print "Extract FunkLoad examples into ./%s : ... " % demo_path,
+    print("Extract FunkLoad examples into ./%s : ... " % demo_path, end=' ')
     cache_path = resource_filename('funkload', 'demo')
     demo_path = os.path.join(os.path.abspath(os.path.curdir), demo_path)
     copytree(cache_path, demo_path)
     cleanup_resources()
-    print "done."
+    print("done.")
 
 
 if __name__ == '__main__':
diff --git a/src/funkload/Distributed.py b/src/funkload/Distributed.py
index 4dcc31b..8a7be5d 100644
--- a/src/funkload/Distributed.py
+++ b/src/funkload/Distributed.py
@@ -16,6 +16,8 @@
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 # 02111-1307, USA.
 #
+from __future__ import print_function
+from __future__ import absolute_import
 import os
 import platform
 import re
@@ -33,7 +35,7 @@
 
 import paramiko
 
-from utils import mmn_encode, trace, package_tests, get_virtualenv_script, \
+from .utils import mmn_encode, trace, package_tests, get_virtualenv_script, \
     get_version
 
 try:
@@ -91,7 +93,7 @@ def requiresconnection(fn):
     def _requiresconnect(self, *args, **kwargs):
         if not self.connected:
             raise RuntimeError(
-                "%s requires an ssh connection to be created" % fn.func_name)
+                "%s requires an ssh connection to be created" % fn.__name__)
         return fn(self, *args, **kwargs)
     _requiresconnect.__name__ = fn.__name__
     _requiresconnect.__doc__ = fn.__doc__
@@ -136,9 +138,9 @@ def __init__(self, name, host, username=None, password=None,
             # print "connect to " + host + " port " + str(port)  + " " + str(credentials)
             self.connection.connect(host, timeout=5, port=port, **credentials)
             self.connected = True
-        except socket.gaierror, error:
+        except socket.gaierror as error:
             self.error = error
-        except socket.timeout, error:
+        except socket.timeout as error:
             self.error = error
         self.killed = False
 
@@ -151,7 +153,7 @@ def get(self, remote_path, local_path):
         try:
             sftp = self.connection.open_sftp()
             sftp.get(remote_path, local_path)
-        except Exception, error:
+        except Exception as error:
             trace("failed to get %s->%s with error %s\n" %
                   (local_path, remote_path, error))
 
@@ -164,7 +166,7 @@ def put(self, local_path, remote_path):
         try:
             sftp = self.connection.open_sftp()
             sftp.put(local_path, remote_path)
-        except Exception, error:
+        except Exception as error:
             trace("failed to put %s->%s with error %s\n" %
                   (local_path, remote_path, error))
 
@@ -223,7 +225,7 @@ def run(self_):
                         self_.exec_command(self.connection, exec_str,
                                            bufsize=1,
                                            timeout=self.channel_timeout)
-                except Exception, e:
+                except Exception as e:
                     if not self.killed:
                         raise
 
@@ -232,7 +234,7 @@ def exec_command(self, connection, command, bufsize=-1, timeout=None):
                 # http://mohangk.org/blog/2011/07/paramiko-sshclient-exec_command-timeout-workaround/
                 chan = connection._transport.open_session()
                 chan.settimeout(timeout)
-                print command
+                print(command)
                 chan.exec_command(command)
                 stdin = chan.makefile('wb', bufsize)
                 stdout = chan.makefile('rb', bufsize)
diff --git a/src/funkload/FunkLoadDocTest.py b/src/funkload/FunkLoadDocTest.py
index cbbfea1..a19500a 100644
--- a/src/funkload/FunkLoadDocTest.py
+++ b/src/funkload/FunkLoadDocTest.py
@@ -19,10 +19,11 @@
 
 $Id$
 """
+from __future__ import absolute_import
 import os
 from tempfile import gettempdir
-from FunkLoadTestCase import FunkLoadTestCase
-import PatchWebunit
+from .FunkLoadTestCase import FunkLoadTestCase
+from . import PatchWebunit
 
 class FunkLoadDocTest(FunkLoadTestCase):
     """Class to use in doctest.
diff --git a/src/funkload/FunkLoadHTTPServer.py b/src/funkload/FunkLoadHTTPServer.py
index 986a75b..43a2d89 100644
--- a/src/funkload/FunkLoadHTTPServer.py
+++ b/src/funkload/FunkLoadHTTPServer.py
@@ -17,11 +17,12 @@
 # 02111-1307, USA.
 
 """Debug HTTPServer module for Funkload."""
+from __future__ import absolute_import
 
 import BaseHTTPServer
 import threading
 import urlparse
-from utils import trace
+from .utils import trace
 
 class FunkLoadHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
     """Handles HTTP requests from client in debug bench mode.
diff --git a/src/funkload/FunkLoadTestCase.py b/src/funkload/FunkLoadTestCase.py
index b4b8a1b..dea14c9 100644
--- a/src/funkload/FunkLoadTestCase.py
+++ b/src/funkload/FunkLoadTestCase.py
@@ -20,6 +20,8 @@
 
 $Id: FunkLoadTestCase.py 24757 2005-08-31 12:22:19Z bdelbosc $
 """
+from __future__ import print_function
+from __future__ import absolute_import
 import os
 import sys
 import time
@@ -44,9 +46,9 @@
 
 from webunit.webunittest import WebTestCase, HTTPError
 
-import PatchWebunit
-from utils import get_default_logger, mmn_is_bench, mmn_decode, Data
-from utils import recording, thread_sleep, is_html, get_version, trace
+from . import PatchWebunit
+from .utils import get_default_logger, mmn_is_bench, mmn_decode, Data
+from .utils import recording, thread_sleep, is_html, get_version, trace
 from xmlrpclib import ServerProxy
 
 _marker = []
@@ -242,7 +244,7 @@ def _connect(self, url, params, ok_codes, rtype, description, redirect=False, co
                                    t_start, t_stop, log_body=True)
                 if self._dumping:
                     self._dump_content(value.response, description)
-                raise self.failureException, str(value.response)
+                raise self.failureException(str(value.response))
             else:
                 self._log_response_error(url, rtype, description, t_start,
                                          t_stop)
@@ -365,7 +367,7 @@ def _browse(self, url_in, params_in=None,
             try:
                 # pageImages is patched to call _log_response on all links
                 self._browser.pageImages(url, page, self)
-            except HTTPError, error:
+            except HTTPError as error:
                 if self._accept_invalid_links:
                     if not self.in_bench_mode:
                         self.logd('  ' + str(error))
@@ -378,7 +380,7 @@ def _browse(self, url_in, params_in=None,
                     # XXX The duration logged for this response is wrong
                     self._log_response(error.response, 'link', None,
                                        t_start, t_stop, log_body=True)
-                    raise self.failureException, str(error)
+                    raise self.failureException(str(error))
             c_stop = self.total_time
             self.logd('  Done in %.3fs' % (c_stop - c_start))
         if sleep:
@@ -810,7 +812,7 @@ def logi(self, message):
         if hasattr(self, 'logger'):
             self.logger.info(self.meta_method_name+': '+message)
         else:
-            print self.meta_method_name+': '+message
+            print(self.meta_method_name+': '+message)
 
     def _logr(self, message, force=False):
         """Log a result."""
@@ -965,7 +967,7 @@ def _dump_content(self, response, description):
         if not response.body:
             return
         if not os.access(dump_dir, os.W_OK):
-            os.mkdir(dump_dir, 0775)
+            os.mkdir(dump_dir, 0o775)
         content_type = response.headers.get('content-type')
         if content_type == 'text/xml':
             ext = '.xml'
diff --git a/src/funkload/Lipsum.py b/src/funkload/Lipsum.py
index 78c5e46..5419e37 100644
--- a/src/funkload/Lipsum.py
+++ b/src/funkload/Lipsum.py
@@ -20,6 +20,7 @@
 
 $Id: Lipsum.py 24649 2005-08-29 14:20:19Z bdelbosc $
 """
+from __future__ import print_function
 import random
 
 # vacabulary simple ascii
@@ -166,27 +167,27 @@ def getAddress(self, lang="fr"):
 
 def main():
     """Testing."""
-    print 'Word: %s\n' % (Lipsum().getWord())
-    print 'UniqWord: %s\n' % (Lipsum().getUniqWord())
-    print 'Subject: %s\n' % (Lipsum().getSubject())
-    print 'Subject uniq: %s\n' % (Lipsum().getSubject(uniq=True))
-    print 'Sentence: %s\n' % (Lipsum().getSentence())
-    print 'Paragraph: %s\n' % (Lipsum().getParagraph())
-    print 'Message: %s\n' % (Lipsum().getMessage())
-    print 'Phone number: %s\n' % Lipsum().getPhoneNumber()
-    print 'Phone number fr short: %s\n' % Lipsum().getPhoneNumber(
-        lang="fr", format="short")
-    print 'Phone number fr medium: %s\n' % Lipsum().getPhoneNumber(
-        lang="fr", format="medium")
-    print 'Phone number fr long: %s\n' % Lipsum().getPhoneNumber(
-        lang="fr", format="long")
-    print 'Phone number en_US short: %s\n' % Lipsum().getPhoneNumber(
-        lang="en_US", format="short")
-    print 'Phone number en_US medium: %s\n' % Lipsum().getPhoneNumber(
-        lang="en_US", format="medium")
-    print 'Phone number en_US long: %s\n' % Lipsum().getPhoneNumber(
-        lang="en_US", format="long")
-    print 'Address default: %s' % Lipsum().getAddress()
+    print('Word: %s\n' % (Lipsum().getWord()))
+    print('UniqWord: %s\n' % (Lipsum().getUniqWord()))
+    print('Subject: %s\n' % (Lipsum().getSubject()))
+    print('Subject uniq: %s\n' % (Lipsum().getSubject(uniq=True)))
+    print('Sentence: %s\n' % (Lipsum().getSentence()))
+    print('Paragraph: %s\n' % (Lipsum().getParagraph()))
+    print('Message: %s\n' % (Lipsum().getMessage()))
+    print('Phone number: %s\n' % Lipsum().getPhoneNumber())
+    print('Phone number fr short: %s\n' % Lipsum().getPhoneNumber(
+        lang="fr", format="short"))
+    print('Phone number fr medium: %s\n' % Lipsum().getPhoneNumber(
+        lang="fr", format="medium"))
+    print('Phone number fr long: %s\n' % Lipsum().getPhoneNumber(
+        lang="fr", format="long"))
+    print('Phone number en_US short: %s\n' % Lipsum().getPhoneNumber(
+        lang="en_US", format="short"))
+    print('Phone number en_US medium: %s\n' % Lipsum().getPhoneNumber(
+        lang="en_US", format="medium"))
+    print('Phone number en_US long: %s\n' % Lipsum().getPhoneNumber(
+        lang="en_US", format="long"))
+    print('Address default: %s' % Lipsum().getAddress())
 
 
 if __name__ == '__main__':
diff --git a/src/funkload/MergeResultFiles.py b/src/funkload/MergeResultFiles.py
index b2a5202..f8a768b 100644
--- a/src/funkload/MergeResultFiles.py
+++ b/src/funkload/MergeResultFiles.py
@@ -17,8 +17,10 @@
 #
 """Merge FunkLoad result files to produce a report for distributed bench
 reports."""
+from __future__ import print_function
+from __future__ import absolute_import
 import xml.parsers.expat
-from utils import trace
+from .utils import trace
 
 class EndOfConfig(Exception):
     pass
@@ -42,23 +44,23 @@ def parse(self, xml_file):
         parser.StartElementHandler = self.handleStartElement
         try:
             parser.ParseFile(file(xml_file))
-        except xml.parsers.expat.ExpatError, msg:
+        except xml.parsers.expat.ExpatError as msg:
             if (self.current_element[-1]['name'] == 'funkload'
                 and str(msg).startswith('no element found')):
-                print "Missing </funkload> tag."
+                print("Missing </funkload> tag.")
             else:
-                print 'Error: invalid xml bench result file'
+                print('Error: invalid xml bench result file')
                 if len(self.current_element) <= 1 or (
                     self.current_element[1]['name'] != 'funkload'):
-                    print """Note that you can generate a report only for a
+                    print("""Note that you can generate a report only for a
                     bench result done with fl-run-bench (and not on a test
-                    result done with fl-run-test)."""
+                    result done with fl-run-test).""")
                 else:
-                    print """You may need to remove non ascii char that comes
+                    print("""You may need to remove non ascii char that comes
                     from error pages catched during the bench. iconv
-                    or recode may help you."""
-                print 'Xml parser element stack: %s' % [
-                    x['name'] for x in self.current_element]
+                    or recode may help you.""")
+                print('Xml parser element stack: %s' % [
+                    x['name'] for x in self.current_element])
                 raise
         except EndOfConfig:
             return
@@ -132,7 +134,7 @@ def __init__(self, input_files, output_file):
                 c += 1
 
             f = open(input_file)
-            for line in f.xreadlines():
+            for line in f:
                 if "</funkload>" in line:
                     continue
                 elif i > 0 and ('<funkload' in line or '<config' in line):
diff --git a/src/funkload/Monitor.py b/src/funkload/Monitor.py
index 1929710..28df33f 100755
--- a/src/funkload/Monitor.py
+++ b/src/funkload/Monitor.py
@@ -19,11 +19,12 @@
 #
 """A Linux monitor server/controller.
 """
+from __future__ import absolute_import
 import sys
 from time import time, sleep
 from threading import Thread
-from XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController
-from MonitorPlugins import MonitorPlugins
+from .XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController
+from .MonitorPlugins import MonitorPlugins
 
 # ------------------------------------------------------------
 # classes
@@ -134,7 +135,7 @@ def _init_cb(self, conf, options):
     def startRecord(self, key):
         """Start to monitor if it is the first key."""
         self.logd('startRecord %s' % key)
-        if not self._keys.has_key(key) or self._keys[key][1] is not None:
+        if key not in self._keys or self._keys[key][1] is not None:
             self._monitor.startRecord()
         self._keys[key] = [len(self.records), None]
         return 1
@@ -142,7 +143,7 @@ def startRecord(self, key):
     def stopRecord(self, key):
         """Stop to monitor if it is the last key."""
         self.logd('stopRecord %s' % key)
-        if not self._keys.has_key(key) or self._keys[key][1] is not None:
+        if key not in self._keys or self._keys[key][1] is not None:
             return 0
         self._keys[key] = [self._keys[key][0], len(self.records)]
         self._monitor.stopRecord()
diff --git a/src/funkload/MonitorPlugins.py b/src/funkload/MonitorPlugins.py
index 1ca06eb..147d852 100644
--- a/src/funkload/MonitorPlugins.py
+++ b/src/funkload/MonitorPlugins.py
@@ -58,7 +58,7 @@ def registerPlugins(self):
 
     def configure(self, config):
         for plugin in self.MONITORS.values():
-            if config.has_key(plugin.name):
+            if plugin.name in config:
                 plugin.setConfig(config[plugin.name])
 
 
diff --git a/src/funkload/MonitorPluginsDefault.py b/src/funkload/MonitorPluginsDefault.py
index f23cbcb..952a9a0 100644
--- a/src/funkload/MonitorPluginsDefault.py
+++ b/src/funkload/MonitorPluginsDefault.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
 # (C) 2012 Nuxeo SAS <http://nuxeo.com>
 # Authors: Krzysztof A. Adamski
 #          bdelbosc@nuxeo.com
@@ -16,7 +17,7 @@
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 # 02111-1307, USA.
 #
-from  MonitorPlugins import MonitorPlugin, Plot
+from  .MonitorPlugins import MonitorPlugin, Plot
 
 
 class MonitorCUs(MonitorPlugin):
diff --git a/src/funkload/PatchWebunit.py b/src/funkload/PatchWebunit.py
index 61c513d..eee352d 100644
--- a/src/funkload/PatchWebunit.py
+++ b/src/funkload/PatchWebunit.py
@@ -32,6 +32,8 @@
 
 $Id: PatchWebunit.py 24649 2005-08-29 14:20:19Z bdelbosc $
 """
+from __future__ import print_function
+from __future__ import absolute_import
 import os
 import sys
 import time
@@ -49,7 +51,7 @@
 from webunit.webunittest import HTTPResponse, HTTPError, VERBOSE
 from webunit.utility import Upload
 
-from utils import thread_sleep, Data
+from .utils import thread_sleep, Data
 import re
 
 valid_url = re.compile(r'^(http|https)://[a-z0-9\.\-\:]+(\/[^\ \t\<\>]*)?$',
@@ -115,7 +117,7 @@ def do_img(self, attributes):
                     continue
                 # TODO: figure the re-write path
                 # newattributes.append((name, path))
-                if not self.session.images.has_key(url):
+                if url not in self.session.images:
                     self.ftestcase.logdd('    img: %s ...' % url)
                     t_start = time.time()
                     self.session.images[url] = self.session.fetch(url)
@@ -146,7 +148,7 @@ def do_link(self, attributes):
                     continue
                 # TODO: figure the re-write path
                 # newattributes.append((name, path))
-                if not self.session.css.has_key(url):
+                if url not in self.session.css:
                     self.ftestcase.logdd('    link: %s ...' % url)
                     t_start = time.time()
                     self.session.css[url] = self.session.fetch(url)
@@ -341,7 +343,7 @@ def WF_fetch(self, url, postdata=None, server=None, port=None, protocol=None,
         else:
             host_header = '%s:%s' % (server, port)
     else:
-        raise ValueError, protocol
+        raise ValueError(protocol)
 
     headers = []
     params = None
@@ -440,7 +442,7 @@ def WF_fetch(self, url, postdata=None, server=None, port=None, protocol=None,
 
     if self.debug_headers:
         for header in headers:
-            print "Putting header -- %s: %s" % header
+            print("Putting header -- %s: %s" % header)
 
     if params is not None:
         h.send(params)
@@ -451,7 +453,7 @@ def WF_fetch(self, url, postdata=None, server=None, port=None, protocol=None,
         errcode = r.status
         errmsg = r.reason
         headers = r.msg
-        if headers is None or headers.has_key('content-length') and headers['content-length'] == "0":
+        if headers is None or 'content-length' in headers and headers['content-length'] == "0":
             data = None
         else:
             data = r.read()
@@ -462,7 +464,7 @@ def WF_fetch(self, url, postdata=None, server=None, port=None, protocol=None,
     else:
         # get the body and save it
         errcode, errmsg, headers = h.getreply()
-        if headers is None or headers.has_key('content-length') and headers['content-length'] == "0":
+        if headers is None or 'content-length' in headers and headers['content-length'] == "0":
             response = HTTPResponse(self.cookies, protocol, server, port, url,
                                     errcode, errmsg, headers, None,
                                     self.error_content)
@@ -514,11 +516,11 @@ def WF_fetch(self, url, postdata=None, server=None, port=None, protocol=None,
                 msg = "Matched error: %s" % content
                 if hasattr(self, 'results') and self.results:
                     self.writeError(url, msg)
-                self.log('Matched error'+`(url, content)`, data)
+                self.log('Matched error'+repr((url, content)), data)
                 if VERBOSE:
                     sys.stdout.write('c')
                     sys.stdout.flush()
-                raise self.failureException, msg
+                raise self.failureException(msg)
 
     if VERBOSE:
         sys.stdout.write('_')
diff --git a/src/funkload/Recorder.py b/src/funkload/Recorder.py
index 5fb0633..0e9b5bd 100644
--- a/src/funkload/Recorder.py
+++ b/src/funkload/Recorder.py
@@ -25,6 +25,8 @@
 
 $Id$
 """
+from __future__ import print_function
+from __future__ import absolute_import
 import os
 import sys
 import re
@@ -34,7 +36,7 @@
 import rfc822
 from cgi import FieldStorage
 from urlparse import urlsplit
-from utils import truncate, trace, get_version, Data
+from .utils import truncate, trace, get_version, Data
 
 
 def get_null_file():
@@ -278,7 +280,7 @@ def searchFiles(self):
         items.sort()
         return [(v['request'], v['response'])
                 for name, v in items
-                if v.has_key('response')]
+                if 'response' in v]
 
     def extractRequests(self, files):
         """Filter and extract request from tcpwatch files."""
@@ -404,7 +406,7 @@ def run(self):
         while count:
             count -= 1
             if count:
-                print "Remaining loop: %i" % count
+                print("Remaining loop: %i" % count)
             if self.tcpwatch_path is None:
                 self.startProxy()
             script = self.extractScript()
@@ -415,8 +417,8 @@ def run(self):
                 self.writeScript(script)
                 self.writeConfiguration()
             else:
-                print script
-                print
+                print(script)
+                print()
             self.tcpwatch_path = None
 
 
diff --git a/src/funkload/ReportBuilder.py b/src/funkload/ReportBuilder.py
index dbbbf7a..2afa134 100644
--- a/src/funkload/ReportBuilder.py
+++ b/src/funkload/ReportBuilder.py
@@ -23,6 +23,8 @@
 
 $Id: ReportBuilder.py 24737 2005-08-31 09:00:16Z bdelbosc $
 """
+from __future__ import print_function
+from __future__ import absolute_import
 
 USAGE = """%prog [options] xmlfile [xmlfile...]
 
@@ -61,15 +63,15 @@
 from optparse import OptionParser, TitledHelpFormatter
 from tempfile import NamedTemporaryFile
 
-from ReportStats import AllResponseStat, PageStat, ResponseStat, TestStat
-from ReportStats import MonitorStat, ErrorStat
-from ReportRenderRst import RenderRst
-from ReportRenderHtml import RenderHtml
-from ReportRenderDiff import RenderDiff
-from ReportRenderTrend import RenderTrend
-from MergeResultFiles import MergeResultFiles
-from utils import trace, get_version
-from apdex import Apdex
+from .ReportStats import AllResponseStat, PageStat, ResponseStat, TestStat
+from .ReportStats import MonitorStat, ErrorStat
+from .ReportRenderRst import RenderRst
+from .ReportRenderHtml import RenderHtml
+from .ReportRenderDiff import RenderDiff
+from .ReportRenderTrend import RenderTrend
+from .MergeResultFiles import MergeResultFiles
+from .utils import trace, get_version
+from .apdex import Apdex
 
 
 # ------------------------------------------------------------
@@ -102,23 +104,23 @@ def parse(self, xml_file):
         """Do the parsing."""
         try:
             self.parser.ParseFile(file(xml_file))
-        except xml.parsers.expat.ExpatError, msg:
+        except xml.parsers.expat.ExpatError as msg:
             if (self.current_element[-1]['name'] == 'funkload'
                 and str(msg).startswith('no element found')):
-                print "Missing </funkload> tag."
+                print("Missing </funkload> tag.")
             else:
-                print 'Error: invalid xml bench result file'
+                print('Error: invalid xml bench result file')
                 if len(self.current_element) <= 1 or (
                     self.current_element[1]['name'] != 'funkload'):
-                    print """Note that you can generate a report only for a
+                    print("""Note that you can generate a report only for a
                     bench result done with fl-run-bench (and not on a test
-                    resu1lt done with fl-run-test)."""
+                    resu1lt done with fl-run-test).""")
                 else:
-                    print """You may need to remove non ascii characters which
+                    print("""You may need to remove non ascii characters which
                     come from error pages caught during the bench test. iconv
-                    or recode may help you."""
-                print 'Xml parser element stack: %s' % [
-                    x['name'] for x in self.current_element]
+                    or recode may help you.""")
+                print('Xml parser element stack: %s' % [
+                    x['name'] for x in self.current_element])
                 raise
 
     def handleStartElement(self, name, attrs):
@@ -305,14 +307,14 @@ def main():
             trace("done: \n")
             trace(html_path + "\n")
         elif options.org:
-            from ReportRenderOrg import RenderOrg
-            print unicode(RenderOrg(xml_parser.config, xml_parser.stats,
+            from .ReportRenderOrg import RenderOrg
+            print(unicode(RenderOrg(xml_parser.config, xml_parser.stats,
                                 xml_parser.error, xml_parser.monitor,
-                                xml_parser.monitorconfig, options)).encode("utf-8")
+                                xml_parser.monitorconfig, options)).encode("utf-8"))
         else:
-            print unicode(RenderRst(xml_parser.config, xml_parser.stats,
+            print(unicode(RenderRst(xml_parser.config, xml_parser.stats,
                                 xml_parser.error, xml_parser.monitor,
-                                xml_parser.monitorconfig, options)).encode("utf-8")
+                                xml_parser.monitorconfig, options)).encode("utf-8"))
 
 
 if __name__ == '__main__':
diff --git a/src/funkload/ReportRenderDiff.py b/src/funkload/ReportRenderDiff.py
index 2e80926..eb3aff5 100644
--- a/src/funkload/ReportRenderDiff.py
+++ b/src/funkload/ReportRenderDiff.py
@@ -19,10 +19,12 @@
 
 $Id$
 """
+from __future__ import print_function
+from __future__ import absolute_import
 import os
-from ReportRenderRst import rst_title
-from ReportRenderHtmlBase import RenderHtmlBase
-from ReportRenderHtmlGnuPlot import gnuplot
+from .ReportRenderRst import rst_title
+from .ReportRenderHtmlBase import RenderHtmlBase
+from .ReportRenderHtmlGnuPlot import gnuplot
 
 def getReadableDiffReportName(a, b):
     """Return a readeable diff report name using 2 reports"""
@@ -82,7 +84,7 @@ def generateReportDirectory(self, output_dir):
         report_dir = os.path.join(output_dir, getReadableDiffReportName(
             self.report_dir1, self.report_dir2))
         if not os.access(report_dir, os.W_OK):
-            os.mkdir(report_dir, 0775)
+            os.mkdir(report_dir, 0o775)
         return report_dir
 
     def createCharts(self):
@@ -147,7 +149,7 @@ def extract_stat(self, tag, report_dir):
         try:
             idx = lines.index("%s stats\n" % tag)
         except ValueError:
-            print "ERROR tag %s not found in rst report %s" % (tag, report_dir)
+            print("ERROR tag %s not found in rst report %s" % (tag, report_dir))
             return []
         delim = 0
         ret =  []
diff --git a/src/funkload/ReportRenderHtml.py b/src/funkload/ReportRenderHtml.py
index d75d7ed..520acea 100644
--- a/src/funkload/ReportRenderHtml.py
+++ b/src/funkload/ReportRenderHtml.py
@@ -19,12 +19,13 @@
 
 $Id: ReportRenderHtml.py 53544 2009-03-09 16:28:58Z tlazar $
 """
+from __future__ import absolute_import
 
 try:
     # 1/ gnuplot
-    from ReportRenderHtmlGnuPlot import RenderHtmlGnuPlot as RenderHtml
+    from .ReportRenderHtmlGnuPlot import RenderHtmlGnuPlot as RenderHtml
 except ImportError:
     # 2/ no charts
-    from ReportRenderHtmlBase import RenderHtmlBase as RenderHtml
+    from .ReportRenderHtmlBase import RenderHtmlBase as RenderHtml
 
-from ReportRenderHtmlGnuPlot import RenderHtmlGnuPlot as RenderHtml
+from .ReportRenderHtmlGnuPlot import RenderHtmlGnuPlot as RenderHtml
diff --git a/src/funkload/ReportRenderHtmlBase.py b/src/funkload/ReportRenderHtmlBase.py
index 66a4abe..eeba905 100644
--- a/src/funkload/ReportRenderHtmlBase.py
+++ b/src/funkload/ReportRenderHtmlBase.py
@@ -22,9 +22,11 @@
 
 $Id$
 """
+from __future__ import print_function
+from __future__ import absolute_import
 import os
 from shutil import copyfile
-from ReportRenderRst import RenderRst, rst_title
+from .ReportRenderRst import RenderRst, rst_title
 
 
 class RenderHtmlBase(RenderRst):
@@ -74,11 +76,11 @@ def prepareReportDirectory(self):
             # init output dir
             output_dir = os.path.abspath(self.options.output_dir)
             if not os.access(output_dir, os.W_OK):
-                os.mkdir(output_dir, 0775)
+                os.mkdir(output_dir, 0o775)
             # init report dir
             report_dir = self.generateReportDirectory(output_dir)
         if not os.access(report_dir, os.W_OK):
-            os.mkdir(report_dir, 0775)
+            os.mkdir(report_dir, 0o775)
         self.report_dir = report_dir
 
     def createRstFile(self):
@@ -133,7 +135,7 @@ def render(self):
             self.generateHtml()
             pass
         except ImportError:
-            print "WARNING docutils not found, no html output."
+            print("WARNING docutils not found, no html output.")
             return ''
         self.createCharts()
         self.copyXmlResult()
diff --git a/src/funkload/ReportRenderHtmlGnuPlot.py b/src/funkload/ReportRenderHtmlGnuPlot.py
index 76ea6c0..3475789 100644
--- a/src/funkload/ReportRenderHtmlGnuPlot.py
+++ b/src/funkload/ReportRenderHtmlGnuPlot.py
@@ -20,17 +20,19 @@
 
 $Id$
 """
+from __future__ import print_function
+from __future__ import absolute_import
 
 import os
 import sys
 import re
 from commands import getstatusoutput
-from apdex import Apdex
-from ReportRenderRst import rst_title
-from ReportRenderHtmlBase import RenderHtmlBase
+from .apdex import Apdex
+from .ReportRenderRst import rst_title
+from .ReportRenderHtmlBase import RenderHtmlBase
 from datetime import datetime
-from MonitorPlugins import MonitorPlugins
-from MonitorPluginsDefault import MonitorCPU, MonitorMemFree, MonitorNetwork, MonitorCUs
+from .MonitorPlugins import MonitorPlugins
+from .MonitorPluginsDefault import MonitorCPU, MonitorMemFree, MonitorNetwork, MonitorCUs
 
 def gnuplot(script_path):
     """Execute a gnuplot script."""
@@ -124,7 +126,7 @@ def createTestChart(self):
         cvus = []
         has_error = False
         for cycle in self.cycles:
-            if not stats[cycle].has_key('test'):
+            if 'test' not in stats[cycle]:
                 continue
             values = []
             test = stats[cycle]['test']
@@ -206,7 +208,7 @@ def createPageChart(self):
         cvus = []
         has_error = False
         for cycle in self.cycles:
-            if not stats[cycle].has_key('page'):
+            if 'page' not in stats[cycle]:
                 continue
             values = []
             page = stats[cycle]['page']
@@ -318,7 +320,7 @@ def createRPSTimeChart(self):
         
         stats = self.stats
 
-        start_timeline = sys.maxint
+        start_timeline = sys.maxsize
         end_timeline = -1
         max_rps = 0
         min_rps = 0
@@ -342,7 +344,7 @@ def createRPSTimeChart(self):
                         
                     f.write('{0} {1}\n'.format(k, st.per_second[k]))
             except Exception as e:
-                print "Exception: {0}".format(e)
+                print("Exception: {0}".format(e))
             finally:
                 f.close
         #print "max rps: {0}".format(max_rps)
@@ -424,7 +426,7 @@ def createAllResponseChart(self):
         cvus = []
         has_error = False
         for cycle in self.cycles:
-            if not stats[cycle].has_key('response'):
+            if 'response' not in stats[cycle]:
                 continue
             values = []
             resp = stats[cycle]['response']
@@ -513,7 +515,7 @@ def createResponseChart(self, step):
         cvus = []
         has_error = False
         for cycle in self.cycles:
-            if not stats[cycle]['response_step'].has_key(step):
+            if step not in stats[cycle]['response_step']:
                 continue
             values = []
             resp = stats[cycle]['response_step'].get(step)
diff --git a/src/funkload/ReportRenderOrg.py b/src/funkload/ReportRenderOrg.py
index af4470b..26b0b36 100644
--- a/src/funkload/ReportRenderOrg.py
+++ b/src/funkload/ReportRenderOrg.py
@@ -17,11 +17,12 @@
 #
 """Classes that render statistics in emacs org-mode format.
 """
+from __future__ import absolute_import
 import re
-from ReportRenderRst import RenderRst
-from ReportRenderRst import BaseRst
-import ReportRenderRst
-from MonitorPlugins import MonitorPlugins
+from .ReportRenderRst import RenderRst
+from .ReportRenderRst import BaseRst
+from . import ReportRenderRst
+from .MonitorPlugins import MonitorPlugins
 
 FL_SITE = "http://funkload.nuxeo.org"
 
diff --git a/src/funkload/ReportRenderRst.py b/src/funkload/ReportRenderRst.py
index 174b34f..2b9fe87 100644
--- a/src/funkload/ReportRenderRst.py
+++ b/src/funkload/ReportRenderRst.py
@@ -19,10 +19,11 @@
 
 $Id$
 """
+from __future__ import absolute_import
 import os
-from utils import get_version
-from apdex import Apdex
-from MonitorPluginsDefault import MonitorCPU, MonitorMemFree, MonitorNetwork, MonitorCUs
+from .utils import get_version
+from .apdex import Apdex
+from .MonitorPluginsDefault import MonitorCPU, MonitorMemFree, MonitorNetwork, MonitorCUs
 
 LI = '*'
 # ------------------------------------------------------------
@@ -264,7 +265,7 @@ def getBestStpsCycle(self):
         max_stps = -1
         cycle_r = None
         for cycle in self.cycles:
-            if not stats[cycle].has_key('test'):
+            if 'test' not in stats[cycle]:
                 continue
             stps = stats[cycle]['test'].tps
             if stps > max_stps:
@@ -281,7 +282,7 @@ def getBestCycle(self):
         max_spps = -1
         cycle_r = None
         for cycle in self.cycles:
-            if not stats[cycle].has_key('page'):
+            if 'page' not in stats[cycle]:
                 continue
             if stats[cycle]['page'].apdex_score < 0.85:
                 continue
@@ -376,15 +377,15 @@ def renderTestContent(self, test):
         total_responses_error = 0
         stats = self.stats
         for cycle in self.cycles:
-            if stats[cycle].has_key('test'):
+            if 'test' in stats[cycle]:
                 total_tests += stats[cycle]['test'].count
                 total_tests_error += stats[cycle]['test'].error
-            if stats[cycle].has_key('page'):
+            if 'page' in stats[cycle]:
                 stat = stats[cycle]['page']
                 stat.finalize()
                 total_pages += stat.count
                 total_pages_error += stat.error
-            if stats[cycle].has_key('response'):
+            if 'response' in stats[cycle]:
                 total_responses += stats[cycle]['response'].count
                 total_responses_error += stats[cycle]['response'].error
         self.append('')
@@ -416,7 +417,7 @@ def renderCyclesStat(self, key, title, description=''):
             self.append('')
         renderer = None
         for cycle in self.cycles:
-            if not stats[cycle].has_key(key):
+            if key not in stats[cycle]:
                 continue
             renderer = klass(stats[cycle][key])
             if first:
@@ -499,7 +500,7 @@ def renderSlowestRequests(self, number):
         self.append(rst_title("Slowest requests", 2))
         cycle = self.getBestCycle()
         cycle_name = None
-        if not (cycle and stats[cycle].has_key('response_step')):
+        if not (cycle and 'response_step' in stats[cycle]):
             return
         steps = stats[cycle]['response_step'].keys()
         items = []
@@ -527,7 +528,7 @@ def renderErrors(self):
             return
         self.append(rst_title("Failures and Errors", 2))
         for status in ('Failure', 'Error'):
-            if not self.error.has_key(status):
+            if status not in self.error:
                 continue
             stats = self.error[status]
             errors = {}
@@ -603,7 +604,7 @@ def __repr__(self):
             return '\n'.join(self.rst)
         cycle_r = self.getRepresentativeCycleStat()
 
-        if cycle_r.has_key('test'):
+        if 'test' in cycle_r:
             self.renderTestContent(cycle_r['test'])
 
         self.renderCyclesStat('test', 'Test stats',
diff --git a/src/funkload/ReportRenderTrend.py b/src/funkload/ReportRenderTrend.py
index 9ac5f6e..64f8cad 100644
--- a/src/funkload/ReportRenderTrend.py
+++ b/src/funkload/ReportRenderTrend.py
@@ -24,11 +24,13 @@
 anykey:anyvalue
 a multi line description in ReST will be displayed in the listing parts
 """
+from __future__ import print_function
+from __future__ import absolute_import
 import os
-from ReportRenderRst import rst_title
-from ReportRenderHtmlBase import RenderHtmlBase
-from ReportRenderHtmlGnuPlot import gnuplot
-from ReportRenderDiff import getRPath
+from .ReportRenderRst import rst_title
+from .ReportRenderHtmlBase import RenderHtmlBase
+from .ReportRenderHtmlGnuPlot import gnuplot
+from .ReportRenderDiff import getRPath
 
 def extract(report_dir, startswith):
     """Extract line form the ReST index file."""
@@ -48,7 +50,7 @@ def extract_date(report_dir):
     tag = "* Launched: "
     value = extract(report_dir, tag)
     if value is None:
-        print "ERROR no date found in rst report %s" % report_dir
+        print("ERROR no date found in rst report %s" % report_dir)
         return "NA"
     return value
 
@@ -58,7 +60,7 @@ def extract_max_cus(report_dir):
     tag = "* Cycles of concurrent users: "
     value = extract(report_dir, tag)
     if value is None:
-        print "ERROR no max CUs found in rst report %s" % report_dir
+        print("ERROR no max CUs found in rst report %s" % report_dir)
         return "NA"
     return value.split(', ')[-1][:-1]
 
@@ -95,7 +97,7 @@ def extract_stat(tag, report_dir):
     try:
         idx = lines.index("%s stats\n" % tag)
     except ValueError:
-        print "ERROR tag %s not found in rst report %s" % (tag, report_dir)
+        print("ERROR tag %s not found in rst report %s" % (tag, report_dir))
         return []
     delim = 0
     ret =  []
@@ -150,7 +152,7 @@ def generateReportDirectory(self, output_dir):
         output_dir = os.path.abspath(output_dir)
         report_dir = os.path.join(output_dir, 'trend-report')
         if not os.access(report_dir, os.W_OK):
-            os.mkdir(report_dir, 0775)
+            os.mkdir(report_dir, 0o775)
         report_dir.replace('\\', '/')
         return report_dir
 
diff --git a/src/funkload/ReportStats.py b/src/funkload/ReportStats.py
index cdbd672..abba9b6 100644
--- a/src/funkload/ReportStats.py
+++ b/src/funkload/ReportStats.py
@@ -19,8 +19,9 @@
 
 $Id: ReportStats.py 24737 2005-08-31 09:00:16Z bdelbosc $
 """
+from __future__ import absolute_import
 
-from apdex import Apdex
+from .apdex import Apdex
 
 
 class MonitorStat:
diff --git a/src/funkload/TestRunner.py b/src/funkload/TestRunner.py
index 98e159e..955c01e 100644
--- a/src/funkload/TestRunner.py
+++ b/src/funkload/TestRunner.py
@@ -26,6 +26,8 @@
 
 $Id: TestRunner.py 24758 2005-08-31 12:33:00Z bdelbosc $
 """
+from __future__ import print_function
+from __future__ import absolute_import
 try:
     import psyco
     psyco.full()
@@ -39,7 +41,7 @@
 import re
 from StringIO import StringIO
 from optparse import OptionParser, TitledHelpFormatter
-from utils import red_str, green_str, get_version
+from .utils import red_str, green_str, get_version
 from funkload.FunkLoadTestCase import FunkLoadTestCase
 
 # ------------------------------------------------------------
@@ -77,7 +79,7 @@ def DTC_runTest(self):
         if failures:
             raise self.failureException(self.format_failure(new.getvalue()))
         elif g_doctest_verbose:
-            print new.getvalue()
+            print(new.getvalue())
 
     DocTestCase.runTest = DTC_runTest
 
@@ -109,7 +111,7 @@ def loadTestsFromModule(self, module):
                 pass
         for name in dir(module):
             obj = getattr(module, name)
-            if (isinstance(obj, (type, types.ClassType)) and
+            if (isinstance(obj, type) and
                 issubclass(obj, unittest.TestCase)):
                 tests.append(self.loadTestsFromTestCase(obj))
         suite = self.suiteClass(tests)
@@ -130,7 +132,7 @@ def loadTestsFromName(self, name, module=None):
         parts = name.split('.')
         if module is None:
             if not parts:
-                raise ValueError, "incomplete test name: %s" % name
+                raise ValueError("incomplete test name: %s" % name)
             else:
                 parts_copy = parts[:]
                 while parts_copy:
@@ -147,24 +149,23 @@ def loadTestsFromName(self, name, module=None):
         import unittest
         if type(obj) == types.ModuleType:
             return self.loadTestsFromModule(obj)
-        elif (isinstance(obj, (type, types.ClassType)) and
+        elif (isinstance(obj, type) and
               issubclass(obj, unittest.TestCase)):
             return self.loadTestsFromTestCase(obj)
         elif type(obj) == types.UnboundMethodType:
             # pass funkload options
-            if issubclass(obj.im_class, FunkLoadTestCase):
-                return obj.im_class(obj.__name__, self.options)
+            if issubclass(obj.__self__.__class__, FunkLoadTestCase):
+                return obj.__self__.__class__(obj.__name__, self.options)
             else:
-                return obj.im_class(obj.__name__)
+                return obj.__self__.__class__(obj.__name__)
         elif callable(obj):
             test = obj()
             if not isinstance(test, unittest.TestCase) and \
                not isinstance(test, unittest.TestSuite):
-                raise ValueError, \
-                      "calling %s returned %s, not a test" % (obj,test)
+                raise ValueError("calling %s returned %s, not a test" % (obj,test))
             return test
         else:
-            raise ValueError, "don't know how to make test from: %s" % obj
+            raise ValueError("don't know how to make test from: %s" % obj)
 
 
 
@@ -215,7 +216,7 @@ def display_testcases(suite):
         if isinstance(test, unittest.TestCase):
             name = test.id()
             name = name[1 + name.find('.'):]
-            print name
+            print(name)
         else:
             display_testcases(test)
 
diff --git a/src/funkload/XmlRpcBase.py b/src/funkload/XmlRpcBase.py
index 9355fb3..c2a7865 100644
--- a/src/funkload/XmlRpcBase.py
+++ b/src/funkload/XmlRpcBase.py
@@ -19,6 +19,7 @@
 
 $Id$
 """
+from __future__ import absolute_import
 import sys, os
 from socket import error as SocketError
 from time import sleep
@@ -28,8 +29,8 @@
 import logging
 from optparse import OptionParser, TitledHelpFormatter
 
-from utils import create_daemon, get_default_logger, close_logger
-from utils import trace, get_version
+from .utils import create_daemon, get_default_logger, close_logger
+from .utils import trace, get_version
 
 
 def is_server_running(host, port):
diff --git a/src/funkload/demo/django_demo/django_test_server/manage.py b/src/funkload/demo/django_demo/django_test_server/manage.py
index bcdd55e..e478d61 100755
--- a/src/funkload/demo/django_demo/django_test_server/manage.py
+++ b/src/funkload/demo/django_demo/django_test_server/manage.py
@@ -1,7 +1,8 @@
 #!/usr/bin/python
+from __future__ import absolute_import
 from django.core.management import execute_manager
 try:
-    import settings # Assumed to be in the same directory.
+    from . import settings # Assumed to be in the same directory.
 except ImportError:
     import sys
     sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
diff --git a/src/funkload/demo/django_demo/django_test_server/methods/urls.py b/src/funkload/demo/django_demo/django_test_server/methods/urls.py
index c071c67..df4e4a8 100644
--- a/src/funkload/demo/django_demo/django_test_server/methods/urls.py
+++ b/src/funkload/demo/django_demo/django_test_server/methods/urls.py
@@ -1,5 +1,6 @@
+from __future__ import absolute_import
 from django.conf.urls.defaults import *
-import views
+from . import views
 from django.views.generic.simple import direct_to_template
 from django.http import HttpResponse
 
diff --git a/src/funkload/rtfeedback.py b/src/funkload/rtfeedback.py
index 7eeb1ae..24790ad 100644
--- a/src/funkload/rtfeedback.py
+++ b/src/funkload/rtfeedback.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import json
 import socket
 try:
@@ -33,7 +34,7 @@ def _handler(self, msg):
         self.pub_sock.send_multipart(['feedback', msg[0]])
 
     def run(self):
-        print 'publisher running in a thread'
+        print('publisher running in a thread')
         self.context = self.context or zmq.Context.instance()
         self.sock = self.context.socket(zmq.PULL)
         self.sock.bind(self.endpoint)
@@ -80,7 +81,7 @@ def _handler(self, msg):
         topic, msg = msg
         msg = json.loads(msg)
         if self.handler is None:
-            print msg
+            print(msg)
         else:
             self.handler(msg, **self.kw)
 
@@ -99,11 +100,11 @@ def stop(self):
 
 
 if __name__ == '__main__':
-    print 'Starting subscriber'
+    print('Starting subscriber')
     sub = FeedbackSubscriber()
-    print 'Listening to events on %r' % sub.pubsub_endpoint
+    print('Listening to events on %r' % sub.pubsub_endpoint)
     try:
         sub.run()
     except KeyboardInterrupt:
         sub.stop()
-        print 'Bye!'
+        print('Bye!')
diff --git a/src/funkload/tests/test_Install.py b/src/funkload/tests/test_Install.py
index 51522d2..181fda8 100644
--- a/src/funkload/tests/test_Install.py
+++ b/src/funkload/tests/test_Install.py
@@ -20,6 +20,7 @@
 
 $Id$
 """
+from __future__ import print_function
 import os
 import sys
 import unittest
@@ -89,14 +90,14 @@ def test_01_requires(self):
         else:
             ret = commands.getstatusoutput('gnuplot --version')
 
-        print ret[1]
+        print(ret[1])
         if ret[0]:
             print ("WARNING: gnuplot is missing, no charts available in "
                    "HTML reports.")
 
         from funkload.TestRunner import g_has_doctest
         if not g_has_doctest:
-            print "WARNING: Python 2.4 is required to support doctest"
+            print("WARNING: Python 2.4 is required to support doctest")
 
 
     def test_testloader(self):
diff --git a/src/funkload/utils.py b/src/funkload/utils.py
index 1d47b12..757e46c 100644
--- a/src/funkload/utils.py
+++ b/src/funkload/utils.py
@@ -65,14 +65,14 @@ def create_daemon():
     """
     try:
         pid = os.fork()
-    except OSError, msg:
-        raise Exception, "%s [%d]" % (msg.strerror, msg.errno)
+    except OSError as msg:
+        raise Exception("%s [%d]" % (msg.strerror, msg.errno))
     if (pid == 0):
         os.setsid()
         try:
             pid = os.fork()
-        except OSError, msg:
-            raise Exception, "%s [%d]" % (msg.strerror, msg.errno)
+        except OSError as msg:
+            raise Exception("%s [%d]" % (msg.strerror, msg.errno))
         if (pid == 0):
             os.umask(0)
         else:
@@ -131,7 +131,7 @@ def get_default_logger(log_to, log_path=None, level=logging.DEBUG,
         if log_dir and not os.path.exists(log_dir):
             try:
                 os.makedirs(log_dir)
-            except Exception, e:
+            except Exception as e:
                 raise Exception("%s, (%s) (%s)" % (e, log_dir, log_path))
     if log_to.count("console"):
         hdlr = logging.StreamHandler()