diff --git a/common/lib/capa/capa/safe_exec/safe_exec.py b/common/lib/capa/capa/safe_exec/safe_exec.py
index 43c2e6ecdd4dea13e1ea85182337889330c9fbf8..794fafb3e1d895633cab41c2b76c88f09247c48b 100644
--- a/common/lib/capa/capa/safe_exec/safe_exec.py
+++ b/common/lib/capa/capa/safe_exec/safe_exec.py
@@ -1,18 +1,21 @@
 """Capa's specialized use of codejail.safe_exec."""
 
-from codejail.safe_exec import safe_exec as codejail_safe_exec
+from __future__ import absolute_import
+
+import hashlib
+
+from codejail.safe_exec import SafeExecException, json_safe
 from codejail.safe_exec import not_safe_exec as codejail_not_safe_exec
-from codejail.safe_exec import json_safe, SafeExecException
-from . import lazymod
+from codejail.safe_exec import safe_exec as codejail_safe_exec
 from six import text_type
 
-import hashlib
+from . import lazymod
 
 # Establish the Python environment for Capa.
 # Capa assumes float-friendly division always.
 # The name "random" is a properly-seeded stand-in for the random module.
 CODE_PROLOG = """\
-from __future__ import division
+from __future__ import absolute_import, division
 
 import os
 os.environ["OPENBLAS_NUM_THREADS"] = "1"    # See TNL-6456
diff --git a/common/lib/capa/capa/safe_exec/tests/test_lazymod.py b/common/lib/capa/capa/safe_exec/tests/test_lazymod.py
index 20e131589cf63dd52cede09da439f6abe791f619..da6018b0b9c4892a857908550c87a71b7d1bbc92 100644
--- a/common/lib/capa/capa/safe_exec/tests/test_lazymod.py
+++ b/common/lib/capa/capa/safe_exec/tests/test_lazymod.py
@@ -1,5 +1,7 @@
 """Test lazymod.py"""
 
+from __future__ import absolute_import
+
 import sys
 import unittest
 
diff --git a/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py b/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py
index c6ae5e24c4d9719c88b00fd83367af8402dbf8f4..3b29b0b43fa192756b40fc321ba3f3f57e5138f5 100644
--- a/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py
+++ b/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py
@@ -1,5 +1,7 @@
 """Test safe_exec.py"""
 
+from __future__ import absolute_import
+
 import hashlib
 import os
 import os.path
@@ -8,11 +10,13 @@ import textwrap
 import unittest
 
 import pytest
-from six import text_type
+import six
+from six import text_type, unichr
+from six.moves import range
+from codejail.jail_code import is_configured
+from codejail.safe_exec import SafeExecException
 
 from capa.safe_exec import safe_exec, update_hash
-from codejail.safe_exec import SafeExecException
-from codejail.jail_code import is_configured
 
 
 class TestSafeExec(unittest.TestCase):
@@ -36,7 +40,7 @@ class TestSafeExec(unittest.TestCase):
     def test_random_seeding(self):
         g = {}
         r = random.Random(17)
-        rnums = [r.randint(0, 999) for _ in xrange(100)]
+        rnums = [r.randint(0, 999) for _ in range(100)]
 
         # Without a seed, the results are unpredictable
         safe_exec("rnums = [random.randint(0, 999) for _ in xrange(100)]", g)
@@ -49,7 +53,7 @@ class TestSafeExec(unittest.TestCase):
     def test_random_is_still_importable(self):
         g = {}
         r = random.Random(17)
-        rnums = [r.randint(0, 999) for _ in xrange(100)]
+        rnums = [r.randint(0, 999) for _ in range(100)]
 
         # With a seed, the results are predictable even from the random module
         safe_exec(
@@ -119,10 +123,10 @@ class TestSafeExecCaching(unittest.TestCase):
         safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
         self.assertEqual(g['a'], 3)
         # A result has been cached
-        self.assertEqual(cache.values()[0], (None, {'a': 3}))
+        self.assertEqual(list(cache.values())[0], (None, {'a': 3}))
 
         # Fiddle with the cache, then try it again.
-        cache[cache.keys()[0]] = (None, {'a': 17})
+        cache[list(cache.keys())[0]] = (None, {'a': 17})
 
         g = {}
         safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
@@ -149,21 +153,21 @@ class TestSafeExecCaching(unittest.TestCase):
 
         # The exception should be in the cache now.
         self.assertEqual(len(cache), 1)
-        cache_exc_msg, cache_globals = cache.values()[0]
+        cache_exc_msg, cache_globals = list(cache.values())[0]
         self.assertIn("ZeroDivisionError", cache_exc_msg)
 
         # Change the value stored in the cache, the result should change.
-        cache[cache.keys()[0]] = ("Hey there!", {})
+        cache[list(cache.keys())[0]] = ("Hey there!", {})
 
         with self.assertRaises(SafeExecException):
             safe_exec(code, g, cache=DictCache(cache))
 
         self.assertEqual(len(cache), 1)
-        cache_exc_msg, cache_globals = cache.values()[0]
+        cache_exc_msg, cache_globals = list(cache.values())[0]
         self.assertEqual("Hey there!", cache_exc_msg)
 
         # Change it again, now no exception!
-        cache[cache.keys()[0]] = (None, {'a': 17})
+        cache[list(cache.keys())[0]] = (None, {'a': 17})
         safe_exec(code, g, cache=DictCache(cache))
         self.assertEqual(g['a'], 17)
 
@@ -171,7 +175,7 @@ class TestSafeExecCaching(unittest.TestCase):
         # Check that using non-ASCII unicode does not raise an encoding error.
         # Try several non-ASCII unicode characters.
         for code in [129, 500, 2 ** 8 - 1, 2 ** 16 - 1]:
-            code_with_unichr = unicode("# ") + unichr(code)
+            code_with_unichr = six.text_type("# ") + unichr(code)
             try:
                 safe_exec(code_with_unichr, {}, cache=DictCache({}))
             except UnicodeEncodeError:
@@ -197,14 +201,14 @@ class TestUpdateHash(unittest.TestCase):
         """
         d1 = {k: 1 for k in "abcdefghijklmnopqrstuvwxyz"}
         d2 = dict(d1)
-        for i in xrange(10000):
+        for i in range(10000):
             d2[i] = 1
-        for i in xrange(10000):
+        for i in range(10000):
             del d2[i]
 
         # Check that our dicts are equal, but with different key order.
         self.assertEqual(d1, d2)
-        self.assertNotEqual(d1.keys(), d2.keys())
+        self.assertNotEqual(list(d1.keys()), list(d2.keys()))
 
         return d1, d2