Re: [ros-users] rospy and python 3.0

Top Page
Attachments:
Message as email
+ (text/plain)
+ python3-support.patch (text/x-patch)
Delete this message
Reply to this message
Author: User discussions
Date:  
To: ros-users
Subject: Re: [ros-users] rospy and python 3.0
Hello,

Short update on the "Python 3 support" front.

We've rebased our work on the trunk of ROS, and I'm happy to annonce
that the 'ros stack' test suite now almost pass on both Python 2.6 and 3.1:

$ cd $ROS_ROOT
$ rosmake -t

I say 'almost' because the test_rospack still fails with this error:


[test_rospack.test_utest/test_ran][FAILURE]-------------------------------------
Unable to find test results for TEST-test_utest.xml, test did not
run. Expected results in .ros/test_results/test_rospack/TEST-test_utest.xml

which does not seem to be related to the port to Python 3 (but I may be
wrong: it may be some side-effect...)

Porting what we did on the rospy package to the SVN trunk is still pending.

Be aware that the new version requires Python >= 2.6 (but I think it was
already assumed from the syntax I saw in the original files).

I had some issues with regexp in junitxml.py:_read_file_safe_xml() so I
commented it out for now.

I've re-organized the GIT repos by stacks, and the changes to the ros
stack are here:
http://code.in.tum.de/indefero/index.php//p/rospy3-stacks-ros/source/tree/master/

Find attached the (huge) patch against SVN trunk.

Comments most welcome!

Severin


-- 
          Séverin Lemaignan - 
  [00]    PhD student on Cognitive Robotics
/|__|\   Technische Uni München - IAS group / LAAS-CNRS - RIS group
   ''     +498928917780 / +33561337844
          http://www.laas.fr/~slemaign

Index: test/test_rosdep/test/test_rosdep_core.py
===================================================================
--- test/test_rosdep/test/test_rosdep_core.py    (revision 12349)
+++ test/test_rosdep/test/test_rosdep_core.py    (working copy)
@@ -139,8 +139,8 @@
             rd.what_needs(["boost"])
             rd.depdb(['rosdep'])
             rd.where_defined(['boost'])
-        except:
-            self.fail("test Rosdep improperly Raised an exception.")
+        except Exception as e:
+            self.fail("test Rosdep improperly Raised an exception: %s"%str(e))


     def test_Rosdep_tripwire(self):
         rd = rosdep.core.Rosdep(["rosdep"], "rosdep", robust=False)
@@ -149,9 +149,8 @@
             rd.what_needs(["boost"])
             rd.depdb(['rosdep'])
             rd.where_defined(['boost'])
-        except:
-            self.fail("test Rosdep improperly Raised an exception.")
-
+        except Exception as e:
+            self.fail("test Rosdep improperly Raised an exception: %s"%str(e))




Index: tools/rosmake/src/rosmake/package_stats.py
===================================================================
--- tools/rosmake/src/rosmake/package_stats.py    (revision 12349)
+++ tools/rosmake/src/rosmake/package_stats.py    (working copy)
@@ -30,8 +30,8 @@


# Author Tully

-from __future__ import with_statement

+
 import os
 import sys, string
 import subprocess
@@ -50,8 +50,8 @@
             osd = roslib.os_detect.OSDetect()
             self.os_name = osd.get_name()
             self.os_version = osd.get_version()
-        except roslib.os_detect.OSDetectException, ex:
-            print >> sys.stderr, "Could not detect OS. platform detection will not work"
+        except roslib.os_detect.OSDetectException as ex:
+            sys.stderr.write("Could not detect OS. platform detection will not work\n")
     else:
         self.os_name = os_name
         self.os_version = os_version
@@ -71,7 +71,7 @@
     return self.paths[package]


   def register_blacklisted(self, blacklisted_package, dependent_package):
-    if dependent_package in self.blacklisted.keys():
+    if dependent_package in list(self.blacklisted.keys()):
       self.blacklisted[dependent_package].append(blacklisted_package)
     else:
       self.blacklisted[dependent_package] = [blacklisted_package] 
Index: tools/rosmake/src/rosmake/parallel_build.py
===================================================================
--- tools/rosmake/src/rosmake/parallel_build.py    (revision 12349)
+++ tools/rosmake/src/rosmake/parallel_build.py    (working copy)
@@ -30,8 +30,8 @@


# Author Tully

-from __future__ import with_statement

+
 import os
 import re
 import distutils.version
@@ -52,7 +52,7 @@
   """
   # Linux, Unix and MacOS:
   if hasattr(os, "sysconf"):
-    if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
+    if "SC_NPROCESSORS_ONLN" in os.sysconf_names:
       # Linux & Unix:
       ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
       if isinstance(ncpus, int) and ncpus > 0:
@@ -60,7 +60,7 @@
     else: # OSX:
       return int(os.popen2("sysctl -n hw.ncpu")[1].read())
   # Windows:
-  if os.environ.has_key("NUMBER_OF_PROCESSORS"):
+  if "NUMBER_OF_PROCESSORS" in os.environ:
     ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]);
     if ncpus > 0:
       return ncpus
@@ -216,7 +216,7 @@
         self.built.append(package)
       else:
         self.failed.append(package)
-      if package in self._started.keys():
+      if package in list(self._started.keys()):
         self._started.pop(package)
       else:
         pass #used early on print "\n\n\nERROR THIS SHOULDN't RETURN %s\n\n\n"%package
Index: tools/rosmake/src/rosmake/__init__.py
===================================================================
--- tools/rosmake/src/rosmake/__init__.py    (revision 12349)
+++ tools/rosmake/src/rosmake/__init__.py    (working copy)
@@ -31,5 +31,5 @@
 is very likely to change in future releases and is not stable.
 """


-from rosmake import RosMakeAll
+from .rosmake import RosMakeAll

Index: tools/rosmake/src/rosmake/rosmake.py
===================================================================
--- tools/rosmake/src/rosmake/rosmake.py    (revision 12349)
+++ tools/rosmake/src/rosmake/rosmake.py    (working copy)
@@ -30,8 +30,8 @@


# Author Tully

-from __future__ import with_statement

+
import os
import re
import distutils.version
@@ -47,15 +47,20 @@
import traceback
import math
import signal
-import exceptions

+try:
+    from exceptions import SystemExit #Python 2.x
+except ImportError:
+    pass #Python 3.x (in Python 3, 'exceptions' is always imported)
+
+
 from operator import itemgetter


-import parallel_build
-import package_stats
-
from optparse import OptionParser

+from . import parallel_build
+from . import package_stats
+
import rosdep

 def make_command():
@@ -121,7 +126,7 @@
         def __exit__(self, mtype, value, tb):
             self.shutdown()
             if value:
-                if not mtype == type(exceptions.SystemExit()):
+                if not mtype == type(SystemExit()):
                     traceback.print_exception(mtype, value, tb)
                 else:
                     sys.exit(value)
@@ -133,7 +138,7 @@
                     self.running = False
                     break
                 self.set_status_from_cache()
-                if len(self.pkg_start_times.keys()) > 0:
+                if len(list(self.pkg_start_times.keys())) > 0:
                     n = self.terminal_width() - len(self.status)
                     status = self.status
                     if n > 0:
@@ -152,7 +157,7 @@


         def rosmake_pkg_times_to_string(self, start_times):
             threads = []
-            for p, t in sorted(start_times.iteritems(), key=itemgetter(1)):
+            for p, t in sorted(iter(start_times.items()), key=itemgetter(1)):
                 threads.append("[ %s: %.1f sec ]"%(p, time.time() - t))


             return " ".join(threads)
@@ -191,7 +196,7 @@


         def print_full_verbose(self, s):
             if self.full_verbose:
-                print "[ rosmake ] %s"%s
+                print("[ rosmake ] %s"%s)


         def print_tail(self, s, tail_lines=40):
             lines = s.splitlines()
@@ -200,13 +205,13 @@


             num_lines = min(len(lines), tail_lines)
             if num_lines == tail_lines:
-                print "[ rosmake ] Last %d lines"%num_lines
+                print("[ rosmake ] Last %d lines"%num_lines)
             else:
-                print "[ rosmake ] All %d lines"%num_lines
-            print "{" + "-"*79
-            for l in xrange(-num_lines, -1):
-                print "  %s"%lines[l]
-            print "-"*79 + "}"
+                print("[ rosmake ] All %d lines"%num_lines)
+            print("{" + "-"*79)
+            for l in range(-num_lines, -1):
+                print("  %s"%lines[l])
+            print("-"*79 + "}")


         def _print_status(self, s):
             sys.stdout.write("%s\r"%(s))
@@ -246,6 +251,7 @@


 class RosMakeAll:
     def __init__(self):
+        
         self._result_lock = threading.Lock()
         self.printer = Printer()
         self.result = {}
@@ -271,7 +277,7 @@
         @return: number of packages that were built
         @rtype: int
         """
-        return len(self.result[argument].keys())
+        return len(list(self.result[argument].keys()))


     def update_status(self, argument, start_times, right):
         self.printer.rosmake_cache_info(argument, start_times, right)
@@ -286,7 +292,7 @@
         try:
             r = rosdep.core.Rosdep(packages, robust=True)
             (output, scripts) = r.check()
-        except roslib.exceptions.ROSLibException, ex:
+        except roslib.exceptions.ROSLibException as ex:
             return ("rosdep ABORTED: %s"%ex, '')


         if len(scripts) > 0:
@@ -312,9 +318,9 @@
                 return None
             else:
                 return "%s"%error
-        except rosdep.core.RosdepException, e:
+        except rosdep.core.RosdepException as e:
             return "%s"%e
-        except roslib.exceptions.ROSLibException, ex:
+        except roslib.exceptions.ROSLibException as ex:
             return "%s"%ex


     def build_or_recurse(self,p):
@@ -325,7 +331,7 @@
         try: # append it ot the list only if present
           self.get_path(p)
           self.build_list.append(p)
-        except roslib.packages.InvalidROSPkgException, ex:
+        except roslib.packages.InvalidROSPkgException as ex:
           if not self.robust_build:
             self.printer.print_all("Exiting due to missing package: %s"%ex)
             sys.exit(-1)
@@ -337,11 +343,11 @@
         self.profile[argument] = {}
         self.output[argument] = {}
         with self._result_lock:
-            if argument not in self.result.keys():
+            if argument not in list(self.result.keys()):
                 self.result[argument] = {}


         cts = []
-        for i in  xrange(0, threads):
+        for i in  range(0, threads):
           ct = parallel_build.CompileThread(str(i), build_queue, self, argument)
           #print "TTTH starting thread ", ct
           ct.start()
@@ -361,7 +367,7 @@
         #print "All threads joined"
         all_pkgs_passed = True
         with self._result_lock:
-            for v in self.result[argument].values():
+            for v in list(self.result[argument].values()):
                 all_pkgs_passed = v and all_pkgs_passed


         build_passed = build_queue.succeeded() and all_pkgs_passed
@@ -372,7 +378,7 @@
     def _subprocess_setup(self):
         # Python installs a SIGPIPE handler by default. This is usually not
         # what non-Python subprocesses expect.
-    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+        signal.signal(signal.SIGPIPE, signal.SIG_DFL)


     def _build_package(self, package, argument=None):
         """
@@ -429,7 +435,7 @@
                     with self._result_lock:
                         self.result[argument][p] = True


-                    num_warnings = len(re.findall("warning:", pstd_out))
+                    num_warnings = len(re.findall("warning:", pstd_out.decode("utf-8")))
                     if num_warnings > 0:
                         return_string =  ("[PASS] [ %.2f seconds ] -- WARNING: %d compiler warnings"%(self.profile[argument][p], num_warnings))
                     else:
@@ -437,8 +443,8 @@
                     self.output_to_file(p, log_type, pstd_out, num_warnings > 0)
                 else:
                     success = False
-                    no_target = len(re.findall("No rule to make target", pstd_out)) > 0
-                    interrupt = len(re.findall("Interrupt", pstd_out)) > 0
+                    no_target = len(re.findall("No rule to make target", pstd_out.decode("utf-8"))) > 0
+                    interrupt = len(re.findall("Interrupt", pstd_out.decode("utf-8"))) > 0
                     if no_target:
                         return_string = ( "[SKIP] No rule to make target %s"%( argument))
                         success = True
@@ -450,7 +456,7 @@
                         self.result[argument][p] = True if no_target else False


                     if success == False: #don't print tail if [SKIP] target
-                        self.printer.print_tail( pstd_out)
+                        self.printer.print_tail( pstd_out.decode("utf-8"))
                     self.output_to_file(p, log_type, pstd_out, always_print= not (no_target or interrupt))


                     return (success, return_string)
@@ -461,7 +467,7 @@
                 return_string += why
                 return(error, return_string)
             return (True, return_string) # this means that we didn't error in any case above
-        except roslib.packages.InvalidROSPkgException, ex:
+        except roslib.packages.InvalidROSPkgException as ex:
             with self._result_lock:
                 self.result[argument][p] = False
             self.printer.print_verbose ("[SKIP] Package not found\n")
@@ -478,7 +484,7 @@
         if not os.path.exists (package_log_dir):
             roslib.rosenv.makedirs_with_parent_perms(package_log_dir)
         with open(std_out_filename, 'w') as stdout_file:
-            stdout_file.write(stdout)
+            stdout_file.write(str(stdout))
             print_string = "Output from build of package %s written to:\n[ rosmake ]    %s"%(package, std_out_filename)
             if always_print:
                 self.printer.print_all(print_string)
@@ -490,13 +496,13 @@
             return


         self.printer.print_all("Results:")
-        if 'clean' in self.result.keys():
+        if 'clean' in list(self.result.keys()):
             self.printer.print_all("Cleaned %d packages."%len(self.result['clean']))
-        if None in self.result.keys():
-            build_failure_count = len([p for p in self.result[None].keys() if self.result[None][p] == False])
+        if None in list(self.result.keys()):
+            build_failure_count = len([p for p in list(self.result[None].keys()) if self.result[None][p] == False])
             self.printer.print_all("Built %d packages with %d failures."%(len(self.result[None]), build_failure_count))
-        if 'test' in self.result.keys():
-            test_failure_count = len([p for p in self.result['test'].keys() if self.result['test'][p] == False])
+        if 'test' in list(self.result.keys()):
+            test_failure_count = len([p for p in list(self.result['test'].keys()) if self.result['test'][p] == False])
             self.printer.print_all("Tested %d packages with %d failures."%(len(self.result['test']), test_failure_count))
         self.printer.print_all("Summary output to directory")
         self.printer.print_all("%s"%self.log_dir)
@@ -509,43 +515,43 @@




-        if None in self.result.keys():
-            if len(self.result[None].keys()) > 0:
+        if None in list(self.result.keys()):
+            if len(list(self.result[None].keys())) > 0:
                 buildfail_filename = os.path.join(log_dir, "buildfailures.txt")
                 with open(buildfail_filename, 'w') as bf:
                     bf.write("Build failures:\n")
                     for key in self.build_list:
-                        if key in self.result[None].keys() and self.result[None][key] == False:
+                        if key in list(self.result[None].keys()) and self.result[None][key] == False:
                             bf.write("%s\n"%key)
-                if  None in self.output.keys():
+                if  None in list(self.output.keys()):
                     buildfail_context_filename = os.path.join(log_dir, "buildfailures-with-context.txt")
                     with open(buildfail_context_filename, 'w') as bfwc:
                         bfwc.write("Build failures with context:\n")
                         for key in self.build_list:
-                            if key in self.result[None].keys() and self.result[None][key] == False:
+                            if key in list(self.result[None].keys()) and self.result[None][key] == False:
                                 bfwc.write("---------------------\n")
                                 bfwc.write("%s\n"%key)
                                 if key in self.output[None]:
                                     bfwc.write(self.output[None][key])


-        if "test" in self.result.keys():
-            if len(self.result["test"].keys()) > 0:
+        if "test" in list(self.result.keys()):
+            if len(list(self.result["test"].keys())) > 0:
                 testfail_filename = os.path.join(log_dir, "testfailures.txt")
                 with open(testfail_filename, 'w') as btwc:
                     btwc.write("Test failures:\n")
                     for key in self.build_list:
-                        if key in self.result["test"].keys() and self.result["test"][key] == False:
+                        if key in list(self.result["test"].keys()) and self.result["test"][key] == False:
                             btwc.write("%s\n"%key)


-                if "test" in self.output.keys():
+                if "test" in list(self.output.keys()):
                     testfail_filename = os.path.join(log_dir, "testfailures-with-context.txt")
                     with open(testfail_filename, 'w') as btwc:
                         btwc.write("Test failures with context:\n")
                         for key in self.build_list:
-                            if key in self.result["test"].keys() and self.result["test"][key] == False:
+                            if key in list(self.result["test"].keys()) and self.result["test"][key] == False:
                                 btwc.write("%s\n"%key)
                                 if key in self.output["test"]:
-                                    btwc.write(self.output["test"][key])
+                                    btwc.write(str(self.output["test"][key]))


         profile_filename = os.path.join(log_dir, "profile.txt")
         with open(profile_filename, 'w') as pf:
@@ -565,26 +571,26 @@
             test_time = 0.0
             build_time = 0.0


-            if None in self.result.keys():
-                if key in self.result[None].keys():
+            if None in list(self.result.keys()):
+                if key in list(self.result[None].keys()):
                     if self.result[None][key] == True:
                         build_result = 1
                     else:
                         build_result = 2


-            if "test" in self.profile.keys():
-                if key in self.result["test"].keys():
+            if "test" in list(self.profile.keys()):
+                if key in list(self.result["test"].keys()):
                     if self.result["test"][key] == True:
                         test_result = 1
                     else:
                         test_result = 2


-            if None in self.profile.keys():
-                if key in self.profile[None].keys():
+            if None in list(self.profile.keys()):
+                if key in list(self.profile[None].keys()):
                     build_time = self.profile[None][key]


-            if "test" in self.profile.keys():
-                if key in self.profile["test"].keys():
+            if "test" in list(self.profile.keys()):
+                if key in list(self.profile["test"].keys()):
                     test_time = self.profile["test"][key]



@@ -616,11 +622,11 @@

                     self.printer.print_verbose(pstd_out)
                     if command_line.returncode:
-                        print >> sys.stderr, "Failed to build %s"%pkg_name
-                        print >> sys.stderr, "Error:\n{{{\n%s\n}}}"%pstd_out
+                        sys.stderr.write("Failed to build %s\n"%pkg_name)
+                        sys.stderr.write("Error:\n{{{\n%s\n}}}\n"%pstd_out)
                         sys.exit(-1)
                     self.printer.print_all("Finished <<< %s"%pkg)
-                except KeyboardInterrupt, ex:
+                except KeyboardInterrupt as ex:
                     self.printer.print_all("Keyboard interrupt caught in pkg %s"%pkg)
                     return False
         return True
@@ -775,7 +781,7 @@
               else:
                 self.printer.print_all("No package selected and the current directory is not the correct path for package '%s'."%p)


-            except roslib.packages.InvalidROSPkgException, ex:
+            except roslib.packages.InvalidROSPkgException as ex:
                 try:
                     stack_dir = roslib.stacks.get_stack_dir(p)
                     if os.path.samefile(stack_dir, '.'):
@@ -911,7 +917,7 @@
           self.printer.print_verbose ("Building packages %s"% self.build_list)
           build_queue = parallel_build.BuildQueue(self.build_list, self.dependency_tracker, robust_build = options.robust or options.best_effort)
           build_queue.register_prebuilt(["rospack"])
-          if None not in self.result.keys():
+          if None not in list(self.result.keys()):
                 self.result[None] = {}
           if 'rospack' in self.build_list:
               self.result[None]["rospack"] = True
Index: tools/rospack/rospack_lite.py
===================================================================
--- tools/rospack/rospack_lite.py    (revision 12349)
+++ tools/rospack/rospack_lite.py    (working copy)
@@ -4,13 +4,13 @@
 import sys, os


if len(sys.argv) < 2:
- print >> sys.stderr, "this version only supports 'find', 'list', and 'list-names'"
+ sys.stderr.write("this version only supports 'find', 'list', and 'list-names'\n")
exit(1);

command = sys.argv[1]

 if not 'ROS_ROOT' in os.environ:
-  print >> sys.stderr, "ROS_ROOT is not defined in the environment"
+  sys.stderr.write("ROS_ROOT is not defined in the environment\n")
   exit(1)
 s = [ os.environ['ROS_ROOT'] ]  # stack of paths to crawl
 if 'ROS_PACKAGE_PATH' in os.environ:
@@ -33,17 +33,17 @@
       s.append(c)


 if command == 'list':
-  for k, v in pkgs.iteritems():
-    print "%s %s" % (k, v)
+  for k, v in pkgs.items():
+    print("%s %s" % (k, v))
 elif command == 'list-names':
-  for k, v in pkgs.iteritems():
-    print k
+  for k, v in pkgs.items():
+    print(k)
 elif command == 'find':
   if len(sys.argv) < 3:
-    print >> sys.stderr, "syntax: rospack find PACKAGE"
+    sys.stderr.write("syntax: rospack find PACKAGE\n")
     exit(1)
   if sys.argv[2] in pkgs:
-    print pkgs[sys.argv[2]]
+    print(pkgs[sys.argv[2]])
 else:
-  print >> sys.stderr, "rospack lite, python style!\nsupported commands:\nrospack find PACKAGE\nrospack list\nrospack list-names\n"
+  sys.stderr.write("rospack lite, python style!\nsupported commands:\nrospack find PACKAGE\nrospack list\nrospack list-names\n\n")


Index: tools/rosunit/scripts/pycoverage_to_html.py
===================================================================
--- tools/rosunit/scripts/pycoverage_to_html.py    (revision 12349)
+++ tools/rosunit/scripts/pycoverage_to_html.py    (working copy)
@@ -38,21 +38,21 @@
 currently a no-frills backend tool.
 """


-from __future__ import with_statement

+
import sys
import roslib

 try:
     import coverage
-except ImportError, e:
-    print >> sys.stderr, "ERROR: cannot import python-coverage, coverage report will not run.\nTo install coverage, run 'easy_install coverage'"
+except ImportError as e:
+    sys.stderr.write("ERROR: cannot import python-coverage, coverage report will not run.\nTo install coverage, run 'easy_install coverage'\n")
     sys.exit(1)


 def coverage_html():
     import os.path
     if not os.path.isfile('.coverage-modules'):
-        print >> sys.stderr, "No .coverage-modules file; nothing to do"
+        sys.stderr.write("No .coverage-modules file; nothing to do\n")
         return


     with open('.coverage-modules','r') as f:
@@ -68,16 +68,16 @@
             roslib.load_manifest(base)
             __import__(m)
         except:
-            print >> sys.stderr, "WARN: cannot import %s"%base
+            sys.stderr.write("WARN: cannot import %s\n"%base)


-    print "Generating for\n"+'\n'.join([" * %s"%m for m in modules])
+    print("Generating for\n"+'\n'.join([" * %s"%m for m in modules]))


     # load the module instances to pass to coverage so it can generate annotation html reports
     mods = []


     # TODO: rewrite, buggy
     for m in modules:
-        mods.extend([v for v in sys.modules.values() if v and v.__name__.startswith(m) and not v in mods])
+        mods.extend([v for v in list(sys.modules.values()) if v and v.__name__.startswith(m) and not v in mods])


     # dump the output to covhtml directory
     cov.html_report(mods, directory="covhtml")
Index: tools/rosunit/scripts/clean_junit_xml.py
===================================================================
--- tools/rosunit/scripts/clean_junit_xml.py    (revision 12349)
+++ tools/rosunit/scripts/clean_junit_xml.py    (working copy)
@@ -33,8 +33,8 @@
 #
 # Revision $Id$


-from __future__ import with_statement

+
"""
clean_junit_xml.py is a simple script that takes all the xml-formatted
Ant JUnit XML test output in test_results and aggregates them into
@@ -53,10 +53,10 @@

 def prepare_dirs(output_dir_name):
     test_results_dir = roslib.rosenv.get_test_results_dir()
-    print "will read test results from", test_results_dir
+    print("will read test results from", test_results_dir)
     output_dir = os.path.join(test_results_dir, output_dir_name)
     if not os.path.exists(output_dir):
-        print "creating directory", output_dir
+        print("creating directory", output_dir)
         os.makedirs(output_dir)
     return test_results_dir, output_dir


@@ -67,7 +67,7 @@
     for d in os.listdir(test_results_dir):
         if filter and d in filter:
             continue
-        print "looking at", d
+        print("looking at", d)
         test_dir = os.path.join(test_results_dir, d)
         if not os.path.isdir(test_dir):
             continue
@@ -84,23 +84,23 @@
                 result = junitxml.read(file, test_name)
                 output_path = os.path.join(output_dir, "%s.xml"%test_name)
                 with open(output_path, 'w') as f:
-                    print "re-writing", output_path
+                    print("re-writing", output_path)
                 f.write(result.xml().encode('utf-8'))
-            except Exception, e:
-                print >> sys.stderr, "ignoring [%s]: %s"%(file, e)
+            except Exception as e:
+                sys.stderr.write("ignoring [%s]: %s\n"%(file, e))


def main():

-    print "[clean_junit_xml]: STARTING"
+    print("[clean_junit_xml]: STARTING")


     output_dir_name = '_hudson'
     test_results_dir, output_dir = prepare_dirs(output_dir_name)


-    print "[clean_junit_xml]: writing aggregated test results to %s"%output_dir
+    print("[clean_junit_xml]: writing aggregated test results to %s"%output_dir)


     clean_results(test_results_dir, output_dir, [output_dir_name, '.svn'])


-    print "[clean_junit_xml]: FINISHED"
+    print("[clean_junit_xml]: FINISHED")


 if __name__ == '__main__':
     main()
Index: tools/rosunit/scripts/check_test_ran.py
===================================================================
--- tools/rosunit/scripts/check_test_ran.py    (revision 12349)
+++ tools/rosunit/scripts/check_test_ran.py    (working copy)
@@ -37,7 +37,7 @@
 Writes a test failure out to test file if it doesn't exist.
 """


-from __future__ import with_statement
+
PKG='rosunit'
NAME="check_test_ran.py"
import roslib; roslib.load_manifest(PKG)
@@ -48,12 +48,13 @@
import rosunit

 def usage():
-    print >> sys.stderr, """Usage:
+    sys.stderr.write("""Usage:
 \t%s test-file.xml
 or
 \t%s --rostest pkg-name test-file.xml
-"""%(NAME, NAME)
-    print sys.argv
+
+"""%(NAME, NAME))
+    print(sys.argv)
     sys.exit(os.EX_USAGE)


 def check_main():
@@ -76,13 +77,13 @@
             usage()
         test_file = sys.argv[1]


-    print "Checking for test results in %s"%test_file
+    print("Checking for test results in %s"%test_file)


     if not os.path.exists(test_file):
         if not os.path.exists(os.path.dirname(test_file)):
             os.makedirs(os.path.dirname(test_file))


-        print "Cannot find results, writing failure results to", test_file
+        print("Cannot find results, writing failure results to", test_file)


         with open(test_file, 'w') as f:
             test_name = os.path.basename(test_file)
Index: tools/rosunit/scripts/summarize_results.py
===================================================================
--- tools/rosunit/scripts/summarize_results.py    (revision 12349)
+++ tools/rosunit/scripts/summarize_results.py    (working copy)
@@ -44,45 +44,43 @@


import os
import sys
-import cStringIO

import roslib.rospack
import rosunit.junitxml as junitxml

 def create_summary(result, packages):
-    buff = cStringIO.StringIO()


-    buff.write('-'*80+'\n')
-    buff.write('\033[1m[AGGREGATED TEST RESULTS SUMMARY]\033[0m\n\n')
+    buff = '-'*80 + '\n'
+    buff += '\033[1m[AGGREGATED TEST RESULTS SUMMARY]\033[0m\n\n'


     errors_failures = [r for r in result.test_case_results if r.errors or r.failures]
     if errors_failures:
-        buff.write('ERRORS/FAILURES:\n')
+        buff += 'ERRORS/FAILURES:\n'
         for tc_result in errors_failures:
-            buff.write(tc_result.description)
+            buff += tc_result.description


-    buff.write("PACKAGES: \n%s\n\n"%'\n'.join([" * %s"%p for p in packages]))
+    buff += "PACKAGES: \n%s\n\n"%'\n'.join([" * %s"%p for p in packages])


-    buff.write('\nSUMMARY\n')
+    buff += '\nSUMMARY\n'
     if (result.num_errors + result.num_failures) == 0:
-        buff.write("\033[32m * RESULT: SUCCESS\033[0m\n")
+        buff += "\033[32m * RESULT: SUCCESS\033[0m\n"
     else:
-        buff.write("\033[1;31m * RESULT: FAIL\033[0m\n")
+        buff += "\033[1;31m * RESULT: FAIL\033[0m\n"


     # TODO: still some issues with the numbers adding up if tests fail to launch


     # number of errors from the inner tests, plus add in count for tests
     # that didn't run properly ('result' object).
-    buff.write(" * TESTS: %s\n"%result.num_tests)
+    buff += " * TESTS: %s\n"%result.num_tests
     if result.num_errors:
-        buff.write("\033[1;31m * ERRORS: %s\033[0m\n"%result.num_errors)
+        buff += "\033[1;31m * ERRORS: %s\033[0m\n"%result.num_errors
     else:
-        buff.write(" * ERRORS: 0\n")
+        buff += " * ERRORS: 0\n"
     if result.num_failures:
-        buff.write("\033[1;31m * FAILURES: %s\033[0m\n"%result.num_failures)
+        buff += "\033[1;31m * FAILURES: %s\033[0m\n"%result.num_failures
     else:
-        buff.write(" * FAILURES: 0\n")
-    return buff.getvalue()
+        buff += " * FAILURES: 0\n"
+    return buff


 def main():
     from optparse import OptionParser
@@ -103,7 +101,7 @@
         packages = [p for p in packages if p]


     result = junitxml.read_all(packages)
-    print create_summary(result, packages)
+    print(create_summary(result, packages))
     if result.num_errors or result.num_failures:
         sys.exit(1)


Index: tools/rosunit/scripts/test_results_dir.py
===================================================================
--- tools/rosunit/scripts/test_results_dir.py    (revision 12349)
+++ tools/rosunit/scripts/test_results_dir.py    (working copy)
@@ -39,4 +39,4 @@
 """


 import roslib.rosenv
-print roslib.rosenv.get_test_results_dir()
+print(roslib.rosenv.get_test_results_dir())
Index: tools/rosunit/src/rosunit/core.py
===================================================================
--- tools/rosunit/src/rosunit/core.py    (revision 12349)
+++ tools/rosunit/src/rosunit/core.py    (working copy)
@@ -32,7 +32,7 @@
 #
 # Revision $Id$


-import os
+import os, sys
import logging
import roslib.rosenv

@@ -45,19 +45,21 @@
     if args:
         msg = msg%args
     _logger.info(msg)
-    print "[ROSUNIT]"+msg
+    print("[ROSUNIT]"+msg)


 def printlog_bold(msg, *args):
     if args:
         msg = msg%args
     _logger.info(msg)
-    print '\033[1m[ROSUNIT]%s\033[0m'%msg
+    #print('\033[1m[ROSUNIT]%s\033[0m'%msg)
+    # For now, removing the ANSI sequence that corrupt the XML result files when running tests
+    print('[ROSUNIT]%s'%msg)


 def printerrlog(msg, *args):
     if args:
         msg = msg%args
     _logger.error(msg)
-    print >> sys.stderr, "[ROSUNIT]"+msg
+    sys.stderr.write("[ROSUNIT] " + msg + "\n")


 def xml_results_file(test_pkg, test_name, is_rostest=False):
     """
@@ -130,7 +132,7 @@
     elif os.path.isfile(test_dir):
         raise Exception("ERROR: cannot run test suite, file is preventing creation of test dir: %s"%test_dir)


-    print "[ROSUNIT] Outputting test results to %s"%results_file
+    print("[ROSUNIT] Outputting test results to %s"%results_file)
     outstream = open(results_file, 'w')
     return XMLTestRunner(stream=outstream)


Index: tools/rosunit/src/rosunit/pyunit.py
===================================================================
--- tools/rosunit/src/rosunit/pyunit.py    (revision 12349)
+++ tools/rosunit/src/rosunit/pyunit.py    (working copy)
@@ -109,10 +109,10 @@
             _cov.load()
             _cov.start()
         except coverage.CoverageException:
-            print >> sys.stderr, "WARNING: you have an older version of python-coverage that is not support. Please update to the version provided by 'easy_install coverage'"
-    except ImportError, e:
-        print >> sys.stderr, """WARNING: cannot import python-coverage, coverage tests will not run.
-To install coverage, run 'easy_install coverage'"""
+            sys.stderr.write("WARNING: you have an older version of python-coverage that is not support. Please update to the version provided by 'easy_install coverage'\n")
+    except ImportError as e:
+        sys.stderr.write("""WARNING: cannot import python-coverage, coverage tests will not run.
+To install coverage, run 'easy_install coverage'\n""")


 def stop_coverage(packages, html=None):
     """
@@ -148,23 +148,23 @@
             # iterate over packages to generate per-package console reports
             for package in packages:
                 pkg = __import__(package)
-                m = [v for v in sys.modules.values() if v and v.__name__.startswith(package)]
+                m = [v for v in list(sys.modules.values()) if v and v.__name__.startswith(package)]
                 all_mods.extend(m)


                 # generate overall report and per module analysis
                 _cov.report(m, show_missing=0)
                 for mod in m:
                     res = _cov.analysis(mod)
-                    print "\n%s:\nMissing lines: %s"%(res[0], res[3])
+                    print("\n%s:\nMissing lines: %s"%(res[0], res[3]))


             if html:


-                print "="*80+"\ngenerating html coverage report to %s\n"%html+"="*80
+                print("="*80+"\ngenerating html coverage report to %s\n"%html+"="*80)
                 _cov.html_report(all_mods, directory=html)
-        except ImportError, e:
-            print >> sys.stderr, "WARNING: cannot import '%s', will not generate coverage report"%package
-    except ImportError, e:
-        print >> sys.stderr, """WARNING: cannot import python-coverage, coverage tests will not run.
-To install coverage, run 'easy_install coverage'"""
+        except ImportError as e:
+            sys.stderr.write("WARNING: cannot import '%s', will not generate coverage report\n"%package)
+    except ImportError as e:
+        sys.stderr.write("""WARNING: cannot import python-coverage, coverage tests will not run.
+To install coverage, run 'easy_install coverage'\n""")



Index: tools/rosunit/src/rosunit/baretest.py
===================================================================
--- tools/rosunit/src/rosunit/baretest.py    (revision 12349)
+++ tools/rosunit/src/rosunit/baretest.py    (working copy)
@@ -38,7 +38,12 @@
 """


 import os
-import cStringIO
+
+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x
+
 import unittest
 import logging
 import time
@@ -142,7 +147,7 @@
                         raise TestTimeoutException("test max time allotted")
                     time.sleep(0.1)


-            except TestTimeoutException, e:
+            except TestTimeoutException as e:
                 if self.retry:
                     timeout_failure = True
                 else:
@@ -241,7 +246,8 @@
         if not os.path.exists(log_dir):
             try:
                 os.makedirs(log_dir)
-            except OSError, (errno, msg):
+            except OSError as err:
+                (errno, msg) = err.args
                 if errno == 13:
                     raise RLException("unable to create directory for log file [%s].\nPlease check permissions."%log_dir)
                 else:
@@ -295,7 +301,7 @@
             # _configure_logging() can mutate self.args
             try:
                 logfileout, logfileerr = self._configure_logging()
-            except Exception, e:
+            except Exception as e:
                 _logger.error(traceback.format_exc())
                 printerrlog("[%s] ERROR: unable to configure logging [%s]"%(self.name, str(e)))
                 # it's not safe to inherit from this process as
@@ -317,7 +323,8 @@


             try:
                 self.popen = subprocess.Popen(self.args, cwd=cwd, stdout=logfileout, stderr=logfileerr, env=full_env, close_fds=True, preexec_fn=os.setsid)
-            except OSError, (errno, msg):
+            except OSError as err:
+                (errno, msg) = err.args
                 self.started = True # must set so is_alive state is correct
                 _logger.error("OSError(%d, %s)", errno, msg)
                 if errno == 8: #Exec format error
@@ -431,7 +438,7 @@
                         #self.popen.wait()
                         #os.wait()
                         _logger.info("process[%s]: sent SIGKILL", self.name)
-                    except OSError, e:
+                    except OSError as e:
                         if e.args[0] == 3:
                             printerrlog("no [%s] process with pid [%s]"%(self.name, pid))
                         else:
@@ -486,7 +493,7 @@
     # (i.e. doesn't check for actual test success). The 'r' result
     # object contains results of the actual tests.


-    buff = cStringIO.StringIO()
+    buff = StringIO()
     buff.write("[%s]"%(runner_name)+'-'*71+'\n\n')
     for tc_result in junit_results.test_case_results:
         buff.write(tc_result.description)
@@ -520,14 +527,14 @@
         for tc_result in runner_results.failures:
             buff.write(" * " +tc_result[0]._testMethodName + "\n")


-    print buff.getvalue()
+    print(buff.getvalue())


 def print_unittest_summary(result):
     """
     Print summary of python unittest result to stdout
     @param result: test results
     """
-    buff = cStringIO.StringIO()
+    buff = StringIO()
     buff.write("-------------------------------------------------------------\nSUMMARY:\n")
     if result.wasSuccessful():
         buff.write("\033[32m * RESULT: SUCCESS\033[0m\n")
@@ -536,5 +543,5 @@
     buff.write(" * TESTS: %s\n"%result.testsRun)
     buff.write(" * ERRORS: %s [%s]\n"%(len(result.errors), ', '.join([e[0]._testMethodName for e in result.errors])))
     buff.write(" * FAILURES: %s [%s]\n"%(len(result.failures), ','.join([e[0]._testMethodName for e in result.failures])))
-    print buff.getvalue()
+    print(buff.getvalue())


Index: tools/rosunit/src/rosunit/pmon.py
===================================================================
--- tools/rosunit/src/rosunit/pmon.py    (revision 12349)
+++ tools/rosunit/src/rosunit/pmon.py    (working copy)
@@ -36,14 +36,19 @@
 Process monitor
 """


-from __future__ import with_statement

+
 import os
 import sys
 import time
 import traceback
 import logging
-import Queue
+
+try:
+    import queue
+except ImportError:
+    import Queue as queue
+
 import atexit
 from threading import Thread, RLock, Lock


@@ -51,6 +56,15 @@

 _logger = logging.getLogger("rosunit")          


+def isstring(s):
+    """Small helper version to check an object is a string in a way that works
+    for both Python 2 and 3
+    """
+    try:
+        return isinstance(s, basestring)
+    except NameError:
+        return isinstance(s, str)
+
 class PmonException(Exception): pass


 class FatalProcessLaunch(PmonException):
@@ -112,7 +126,7 @@
         else:
             _logger.debug("shutdown_process_monitor: ProcessMonitor shutdown succeeded")
             return True
-    except Exception, e:
+    except Exception as e:
         return False


 _shutdown_lock = Lock()
@@ -341,7 +355,7 @@
         method was called.
         @rtype: bool
         """
-        if not isinstance(name, basestring):
+        if not isstring(name):
             raise PmonException("kill_process takes in a process name but was given: %s"%name)
         _logger.debug("ProcessMonitor.kill_process[%s]"%name)
         printlog("[%s] kill requested"%name)
@@ -436,7 +450,7 @@
                         for l in self.listeners:
                             l.process_died(p.name, p.exit_code)


-                except Exception, e:
+                except Exception as e:
                     traceback.print_exc()
                     #don't respawn as this is an internal error
                     dead.append(p)
@@ -482,7 +496,7 @@
         self.is_shutdown = True
         # killall processes on run exit


-        q = Queue.Queue()
+        q = queue.Queue()
         q.join()


         with self.plock:
@@ -559,7 +573,7 @@
                 p = q.get(False)
                 _kill_process(p, self.errors)
                 q.task_done()
-            except Queue.Empty:
+            except queue.Empty:
                 pass



Index: tools/rosunit/src/rosunit/junitxml.py
===================================================================
--- tools/rosunit/src/rosunit/junitxml.py    (revision 12349)
+++ tools/rosunit/src/rosunit/junitxml.py    (working copy)
@@ -39,7 +39,12 @@


 import os
 import sys
-import cStringIO
+
+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x
+
 import string
 import codecs
 import re
@@ -69,14 +74,14 @@
     'error' result container        
     """
     def xml(self):
-        return u'<error type="%s"><![CDATA[%s]]></error>'%(self.type, self.text)            
+        return '<error type="%s"><![CDATA[%s]]></error>'%(self.type, self.text)            


 class TestFailure(TestInfo):
     """
     'failure' result container        
     """
     def xml(self):
-        return u'<failure type="%s"><![CDATA[%s]]></failure>'%(self.type, self.text)            
+        return '<failure type="%s"><![CDATA[%s]]></failure>'%(self.type, self.text)            



 class TestCaseResult(object):
@@ -153,7 +158,7 @@
         self.errors.append(error)


     def xml(self):
-        return u'  <testcase classname="%s" name="%s" time="%s">\n'%(self.classname, self.name, self.time)+\
+        return '  <testcase classname="%s" name="%s" time="%s">\n'%(self.classname, self.name, self.time)+\
                '\n    '.join([f.xml() for f in self.failures])+\
                '\n    '.join([e.xml() for e in self.errors])+\
                '  </testcase>'
@@ -198,7 +203,7 @@
         """
         @return: document as unicode (UTF-8 declared) XML according to Ant JUnit spec
         """
-        return u'<?xml version="1.0" encoding="utf-8"?>'+\
+        return '<?xml version="1.0" encoding="utf-8"?>'+\
                '<testsuite name="%s" tests="%s" errors="%s" failures="%s" time="%s">'%\
                (self.name, self.num_tests, self.num_errors, self.num_failures, self.time)+\
                '\n'.join([tc.xml() for tc in self.test_case_results])+\
@@ -207,7 +212,10 @@
                '</testsuite>'


 def _text(tag):
-    return reduce(lambda x, y: x + y, [c.data for c in tag.childNodes if c.nodeType in [DomNode.TEXT_NODE, DomNode.CDATA_SECTION_NODE]], "").strip()
+    res = ""
+    for n in [c.data for c in tag.childNodes if c.nodeType in [DomNode.TEXT_NODE, DomNode.CDATA_SECTION_NODE]]:
+        res += n.strip()
+    return res


 def _load_suite_results(test_suite_name, test_suite, result):
     nodes = [n for n in test_suite.childNodes \
@@ -260,17 +268,6 @@
                     x = TestError(d.getAttribute('type') or '', text)
                     tc_result.add_error(x)


-## #603: unit test suites are not good about screening out illegal
-## unicode characters. This little recipe I from http://boodebr.org/main/python/all-about-python-and-unicode#UNI_XML
-## screens these out
-RE_XML_ILLEGAL = u'([\u0000-\u0008\u000b-\u000c\u000e-\u001f\ufffe-\uffff])' + \
-                 u'|' + \
-                 u'([%s-%s][^%s-%s])|([^%s-%s][%s-%s])|([%s-%s]$)|(^[%s-%s])' % \
-                 (unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff),
-                  unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff),
-                  unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff))
-_safe_xml_regex = re.compile(RE_XML_ILLEGAL)
-
 def _read_file_safe_xml(test_file):
     """
     read in file, screen out unsafe unicode characters
@@ -286,9 +283,24 @@
             f = codecs.open(test_file, "r", "iso8859-1" )
             x = f.read()        


-        for match in _safe_xml_regex.finditer(x):
-            x = x[:match.start()] + "?" + x[match.end():]
-        return x.encode("utf-8")
+        ## #603: unit test suites are not good about screening out illegal
+        ## unicode characters. This little recipe I from http://boodebr.org/main/python/all-about-python-and-unicode#UNI_XML
+        ## screens these out
+
+        if sys.version_info[0] < 3:
+            #~ RE_XML_ILLEGAL = '([\u0000-\u0008\u000b-\u000c\u000e-\u001f\ufffe-\uffff])' + \
+                             #~ '|' + \
+                             #~ '([%s-%s][^%s-%s])|([^%s-%s][%s-%s])|([%s-%s]$)|(^[%s-%s])' % \
+                             #~ (chr(0xd800),chr(0xdbff),chr(0xdc00),chr(0xdfff),
+                              #~ chr(0xd800),chr(0xdbff),chr(0xdc00),chr(0xdfff),
+                              #~ chr(0xd800),chr(0xdbff),chr(0xdc00),chr(0xdfff))
+            #~ _safe_xml_regex = re.compile(RE_XML_ILLEGAL)
+            #~ 
+            #~ for match in _safe_xml_regex.finditer(x):
+                #~ x = x[:match.start()] + "?" + x[match.end():]
+            return x.encode("utf-8")
+        else: #Python 3 unicode support *should* handle everything. Not throughfully tested however :-)
+            return x
     finally:
         f.close()


@@ -305,18 +317,18 @@
     try:
         xml_str = _read_file_safe_xml(test_file)
         test_suite = parseString(xml_str).getElementsByTagName('testsuite')
-    except Exception, e:
+    except Exception as e:
         import traceback
         traceback.print_exc()
-        print "WARN: cannot read test result file [%s]: %s"%(test_file, str(e))
+        print("WARN: cannot read test result file [%s]: %s"%(test_file, str(e)))
         return Result(test_name, 0, 0, 0)
     if not test_suite:
-        print "WARN: test result file [%s] contains no results"%test_file
+        print("WARN: test result file [%s] contains no results"%test_file)
         return Result(test_name, 0, 0, 0)
     test_suite = test_suite[0]
     vals = [test_suite.getAttribute(attr) for attr in ['errors', 'failures', 'tests']]
     vals = [v or 0 for v in vals]
-    err, fail, tests = [string.atoi(val) for val in vals]
+    err, fail, tests = [int(val) for val in vals]


     result = Result(test_name, err, fail, tests)
     result.time = test_suite.getAttribute('time') or 0.0    
@@ -410,32 +422,31 @@
     # (i.e. doesn't check for actual test success). The 'r' result
     # object contains results of the actual tests.


-    buff = cStringIO.StringIO()
-    buff.write("[%s]"%runner_name+'-'*71+'\n\n')
+    buff = "[%s]"%runner_name+'-'*71+'\n\n'
     for tc_result in junit_results.test_case_results:
-        buff.write(tc_result.description)
+        buff += tc_result.description


-    buff.write('\nSUMMARY\n')
+    buff += '\nSUMMARY\n'
     if (junit_results.num_errors + junit_results.num_failures) == 0:
-        buff.write("\033[32m * RESULT: SUCCESS\033[0m\n")
+        buff += "\033[32m * RESULT: SUCCESS\033[0m\n"
     else:
-        buff.write("\033[1;31m * RESULT: FAIL\033[0m\n")
+        buff += "\033[1;31m * RESULT: FAIL\033[0m\n"


     # TODO: still some issues with the numbers adding up if tests fail to launch


     # number of errors from the inner tests, plus add in count for tests
     # that didn't run properly ('result' object).
-    buff.write(" * TESTS: %s\n"%junit_results.num_tests)
+    buff += " * TESTS: %s\n"%junit_results.num_tests
     num_errors = junit_results.num_errors
     if num_errors:
-        buff.write("\033[1;31m * ERRORS: %s\033[0m\n"%num_errors)
+        buff += "\033[1;31m * ERRORS: %s\033[0m\n"%num_errors
     else:
-        buff.write(" * ERRORS: 0\n")
+        buff += " * ERRORS: 0\n"
     num_failures = junit_results.num_failures
     if num_failures:
-        buff.write("\033[1;31m * FAILURES: %s\033[0m\n"%num_failures)
+        buff += "\033[1;31m * FAILURES: %s\033[0m\n"%num_failures
     else:
-        buff.write(" * FAILURES: 0\n")
+        buff += " * FAILURES: 0\n"


-    print buff.getvalue()
+    print(buff)


Index: tools/rosunit/src/rosunit/xmlrunner.py
===================================================================
--- tools/rosunit/src/rosunit/xmlrunner.py    (revision 12349)
+++ tools/rosunit/src/rosunit/xmlrunner.py    (working copy)
@@ -13,12 +13,15 @@
 import time
 import traceback
 import unittest
-from StringIO import StringIO
+
+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x
+    
 from xml.sax.saxutils import escape


-from StringIO import StringIO

-
class _TestInfo(object):

     """Information about a particular test.
@@ -357,7 +360,7 @@
         """
         class TestTest(unittest.TestCase):
             def test_foo(self):
-                print "Test"
+                print("Test")
         self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
   <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
   <system-out><![CDATA[Test
@@ -373,7 +376,7 @@
         """
         class TestTest(unittest.TestCase):
             def test_foo(self):
-                print >>sys.stderr, "Test"
+                sys.stderr.write("Test\n")
         self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
   <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
   <system-out><![CDATA[]]></system-out>
Index: tools/rosunit/src/rosunit/rosunit_main.py
===================================================================
--- tools/rosunit/src/rosunit/rosunit_main.py    (revision 12349)
+++ tools/rosunit/src/rosunit/rosunit_main.py    (working copy)
@@ -32,8 +32,8 @@
 #
 # Revision $Id$


-from __future__ import with_statement

+
 import os
 import sys
 import time
@@ -56,7 +56,7 @@
     logfile_basename = 'rosunit-%s.log'%(test_name)
     logfile_name = roslib.roslogging.configure_logging('rosunit-%s'%(test_name), filename=logfile_basename)
     if logfile_name:
-        print "... logging to %s"%logfile_name
+        print("... logging to %s"%logfile_name)
     return logfile_name


 def rosunitmain():
@@ -122,10 +122,10 @@
     if not options.text_mode:
         print_runner_summary(runner_result, results)
     else:
-        print "WARNING: overall test result is not accurate when --text is enabled"
+        print("WARNING: overall test result is not accurate when --text is enabled")


     if logfile_name:
-        print "rosunit log file is in %s"%logfile_name
+        print("rosunit log file is in %s"%logfile_name)


     if not runner_result.wasSuccessful():
         sys.exit(1)
Index: tools/rosboost_cfg/src/rosboost_cfg/rosboost_cfg.py
===================================================================
--- tools/rosboost_cfg/src/rosboost_cfg/rosboost_cfg.py    (revision 12349)
+++ tools/rosboost_cfg/src/rosboost_cfg/rosboost_cfg.py    (working copy)
@@ -38,8 +38,12 @@
 import subprocess
 import platform
 from optparse import OptionParser
-from cStringIO import StringIO


+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x
+
 lib_suffix = "so"
 if (sys.platform == "darwin"):
   lib_suffix = "dylib"
@@ -60,12 +64,12 @@
         boost_version.append(0)


 def print_usage_and_exit():
-  print >> sys.stderr, "Usage: rosboost-cfg --lflags [thread,regex,graph,...]"
-  print >> sys.stderr, "       rosboost-cfg --cflags"
-  print >> sys.stderr, "       rosboost-cfg --libs [thread,regex,graph,...]"
-  print >> sys.stderr, "       rosboost-cfg --include_dirs"
-  print >> sys.stderr, "       rosboost-cfg --lib_dirs"
-  print >> sys.stderr, "       rosboost-cfg --root"
+  print("Usage: rosboost-cfg --lflags [thread,regex,graph,...]")
+  print("       rosboost-cfg --cflags")
+  print("       rosboost-cfg --libs [thread,regex,graph,...]")
+  print("       rosboost-cfg --include_dirs")
+  print("       rosboost-cfg --lib_dirs")
+  print("       rosboost-cfg --root")
   sys.exit(1)


 class BoostError(Exception):
@@ -270,19 +274,18 @@
         return ' -l%s'%(os.path.splitext(lib)[0][len('lib'):])


 def lflags(ver, libs):
-    s = StringIO()
-    print >> s, lib_dir_flags(ver),
+    s= lib_dir_flags(ver) + " "
     for lib in libs:
-        print >> s, lib_flags(ver, lib),
+        s += lib_flags(ver, lib) + " "


-    return s.getvalue()
+    return s


 def libs(ver, libs):
-    s = StringIO()
+    s = ""
     for lib in libs:
-        print >> s, find_lib(ver, lib, True),
+        s += find_lib(ver, lib, True) + " "


-    return s.getvalue()
+    return s


 def lib_dirs(ver):
     if (ver.is_default_search_location or no_L_or_I):
@@ -319,7 +322,7 @@
     if (options.print_versions):
         check_one_option(options, 'print_versions')
         for ver in find_versions(search_paths(options.sysroot)):
-            print '%s.%s.%s root=%s include_dir=%s'%(ver.major, ver.minor, ver.patch, ver.root, ver.include_dir)
+            print('%s.%s.%s root=%s include_dir=%s'%(ver.major, ver.minor, ver.patch, ver.root, ver.include_dir))
         return


     ver = find_boost(search_paths(options.sysroot))
@@ -330,7 +333,7 @@


     if (options.version):
         check_one_option(options, 'version')
-        print '%s.%s.%s root=%s include_dir=%s'%(ver.major, ver.minor, ver.patch, ver.root, ver.include_dir)
+        print('%s.%s.%s root=%s include_dir=%s'%(ver.major, ver.minor, ver.patch, ver.root, ver.include_dir))
         return


     if (ver.major < 1 or (ver.major == 1 and ver.minor < 37)):
@@ -360,7 +363,7 @@
     else:
         print_usage_and_exit()


-    print output.strip()
+    print(output.strip())


 if __name__ == "__main__":
     main()
Index: tools/rosboost_cfg/src/rosboost_cfg/__init__.py
===================================================================
--- tools/rosboost_cfg/src/rosboost_cfg/__init__.py    (revision 12349)
+++ tools/rosboost_cfg/src/rosboost_cfg/__init__.py    (working copy)
@@ -30,4 +30,4 @@
 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 # POSSIBILITY OF SUCH DAMAGE.


-from rosboost_cfg import *
+from .rosboost_cfg import *
Index: tools/rosdep/src/rosdep/core.py
===================================================================
--- tools/rosdep/src/rosdep/core.py    (revision 12349)
+++ tools/rosdep/src/rosdep/core.py    (working copy)
@@ -32,8 +32,8 @@
 #Library and command-line tool for calculating rosdeps.
 #"""


-from __future__ import with_statement

+
import roslib.rospack
import roslib.stacks
import roslib.manifest
@@ -58,7 +58,7 @@


 yaml.add_constructor(
-    u'tag:yaml.org,2002:float',
+    'tag:yaml.org,2002:float',
     yaml.constructor.Constructor.construct_yaml_str)


 class YamlCache:
@@ -83,8 +83,8 @@
                 self._yaml_cache[path] = yaml.load(yaml_text)
                 return self._yaml_cache[path]


-            except yaml.YAMLError, exc:
-                print >> sys.stderr, "Failed parsing yaml while processing %s\n"%path, exc
+            except yaml.YAMLError as exc:
+                sys.stderr.write("Failed parsing yaml while processing %s: %s\n"%(path, exc))
                 #sys.exit(1)        # not a breaking error
         self._yaml_cache[path] = {}
         return {}
@@ -128,7 +128,7 @@
         if type(os_specific) == type("String"):
             return os_specific
         else:# it must be a map of versions
-            if self.os_version in os_specific.keys():
+            if self.os_version in list(os_specific.keys()):
                 return os_specific[self.os_version]
             #print >> sys.stderr, "failed to find definition of %s for OS(%s) Version(%s) within '''%s'''. Defined in file %s"%(rosdep_name, self.os_name, self.os_version, os_specific, source_path)
             return False                    
@@ -173,9 +173,9 @@
         try:
             rosdep_dependent_packages = ros_package_proxy.depends([package])[package]
             #print "package", package, "needs", rosdep_dependent_packages
-        except KeyError, ex:
-            print "Depends Failed on package", ex
-            print " The errors was in ",  ros_package_proxy.depends([package])
+        except KeyError as ex:
+            print("Depends Failed on package", ex)
+            print(" The errors was in ",  ros_package_proxy.depends([package]))
             rosdep_dependent_packages = []
         #print "Dependents of", package, rosdep_dependent_packages
         rosdep_dependent_packages.append(package)
@@ -186,25 +186,25 @@
             stack = None
             try:
                 stack = roslib.stacks.stack_of(p)
-            except roslib.packages.InvalidROSPkgException, ex:
-                print >> sys.stderr, "Failed to find stack for package [%s]"%p
+            except roslib.packages.InvalidROSPkgException as ex:
+                sys.stderr.write("Failed to find stack for package [%s]\n"%p)
                 pass
             if stack:
                 try:
                     paths.add( os.path.join(roslib.stacks.get_stack_dir(stack), "rosdep.yaml"))
-                except AttributeError, ex:
-                    print "Stack [%s] could not be found"%(stack)
+                except AttributeError as ex:
+                    print("Stack [%s] could not be found"%(stack))
                 for s in self.yaml_cache.get_rosstack_depends(stack):
                     try:
                         paths.add( os.path.join(roslib.stacks.get_stack_dir(s), "rosdep.yaml"))
-                    except AttributeError, ex:
-                        print "Stack [%s] dependency of [%s] could not be found"%(s, stack)
+                    except AttributeError as ex:
+                        print("Stack [%s] dependency of [%s] could not be found"%(s, stack))


             else:
                 try:
                     paths.add( os.path.join(roslib.packages.get_pkg_dir(p), "rosdep.yaml"))
-                except roslib.packages.InvalidROSPkgException, ex:
-                    print >> sys.stderr, "Failed to load rosdep.yaml for package [%s]:%s"%(p, ex)
+                except roslib.packages.InvalidROSPkgException as ex:
+                    sys.stderr.write("Failed to load rosdep.yaml for package [%s]:%s"%(p, ex))
                     pass
         for path in paths:
             self.insert_map(self.parse_yaml(path), path)
@@ -225,7 +225,7 @@



                 if override:
-                    print >>sys.stderr, "ROSDEP_OVERRIDE: %s being overridden with %s from %s"%(key, yaml_dict[key], source_path)
+                    sys.stderr.write("ROSDEP_OVERRIDE: %s being overridden with %s from %s"%(key, yaml_dict[key], source_path))
                     self.rosdep_source[key].append("Overriding with "+source_path)
                     self.rosdep_map[key] = rosdep_entry
                 else:
@@ -258,7 +258,7 @@
         if rosdep in self.rosdep_map:
             return self.rosdep_map[rosdep]
         else:
-            print >> sys.stderr, "Failed to find rosdep %s for package %s on OS:%s version:%s"%(rosdep, self.package, self.os_name, self.os_version)
+            sys.stderr.write("Failed to find rosdep %s for package %s on OS:%s version:%s"%(rosdep, self.package, self.os_name, self.os_version))
             return False


     def get_map(self):
@@ -307,7 +307,7 @@
         yc = YamlCache(self.osi.get_name(), self.osi.get_version())
         start_time = time.time()
         if "ROSDEP_DEBUG" in os.environ:
-            print "Generating package list and scripts for %d rosdeps.  This may take a few seconds..."%len(self.packages)
+            print("Generating package list and scripts for %d rosdeps.  This may take a few seconds..."%len(self.packages))
         for p in self.packages:
             rdlp = RosdepLookupPackage(self.osi.get_name(), self.osi.get_version(), p, yc)
             for r in self.rosdeps[p]:
@@ -325,11 +325,11 @@
             if not self.robust:
                 raise RosdepException("ABORTING: Rosdeps %s could not be resolved"%failed_rosdeps)
             else:
-                print >> sys.stderr, "WARNING: Rosdeps %s could not be resolved"%failed_rosdeps
+                sys.stderr.write("WARNING: Rosdeps %s could not be resolved"%failed_rosdeps)


         time_delta = (time.time() - start_time)
         if "ROSDEP_DEBUG" in os.environ:
-            print "Done loading rosdeps in %f seconds, averaging %f per rosdep."%(time_delta, time_delta/len(self.packages))
+            print("Done loading rosdeps in %f seconds, averaging %f per rosdep."%(time_delta, time_delta/len(self.packages)))


         return (list(set(native_packages)), list(set(scripts)))


@@ -348,8 +348,8 @@
         scripts = []
         try:
             native_packages, scripts = self.get_packages_and_scripts()
-        except RosdepException, e:
-            print >> sys.stderr, e
+        except RosdepException as e:
+            sys.stderr.write(str(e) + "\n")
             pass
         undetected = self.osi.get_os().strip_detected_packages(native_packages)
         return_str = ""
@@ -378,7 +378,7 @@
             fh.write(script)
             fh.flush()


-            print "rosdep executing this script:\n{{{\n%s\n}}}"%script
+            print("rosdep executing this script:\n{{{\n%s\n}}}"%script)
             p= subprocess.Popen(['bash', fh.name], stderr=subprocess.PIPE )
             (out, err) = p.communicate()
             if p.returncode != 0:
Index: tools/rosdep/src/rosdep/freebsd.py
===================================================================
--- tools/rosdep/src/rosdep/freebsd.py    (revision 12349)
+++ tools/rosdep/src/rosdep/freebsd.py    (working copy)
@@ -31,7 +31,7 @@


import os
import roslib.os_detect
-import base_rosdep
+from . import base_rosdep

 ###### FreeBSD SPECIALIZATION #########################
 def port_detect(p):
@@ -63,7 +63,7 @@
             return "#No Packages to install"
         if default_yes:
             import sys
-            print >> sys.stderr, "pkg_add does not have a default_yes option, continuing without"
+            sys.stderr.write("pkg_add does not have a default_yes option, continuing without\n")
         return "#Packages\nsudo /usr/sbin/pkg_add -r " + ' '.join(packages)


 ###### END FreeBSD SPECIALIZATION ########################
Index: tools/rosdep/src/rosdep/gentoo.py
===================================================================
--- tools/rosdep/src/rosdep/gentoo.py    (revision 12349)
+++ tools/rosdep/src/rosdep/gentoo.py    (working copy)
@@ -26,7 +26,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 # POSSIBILITY OF SUCH DAMAGE.


-from __future__ import with_statement
+
 import os.path
 import roslib.os_detect
 import subprocess
@@ -67,6 +67,6 @@
         elif equery_available():
             return "#Packages\nsudo emerge " + ' '.join(packages)
         else:
-        return "#Packages\nsudo emerge -u " + ' '.join(packages)
+            return "#Packages\nsudo emerge -u " + ' '.join(packages)


 ###### END Gentoo SPECIALIZATION ########################
Index: tools/rosdep/src/rosdep/arch.py
===================================================================
--- tools/rosdep/src/rosdep/arch.py    (revision 12349)
+++ tools/rosdep/src/rosdep/arch.py    (working copy)
@@ -28,8 +28,8 @@


# Author Tully

-from __future__ import with_statement
-from linux_helpers import *
+
+from .linux_helpers import *
import os

 import rosdep.base_rosdep
@@ -58,7 +58,7 @@
                 if os_list[0] == "Linux" and os_list[1] == "Arch":
                     return os_list[2]
         except:
-            print "Arch failed to get version"
+            print("Arch failed to get version")
             return False


         return False
Index: tools/rosdep/src/rosdep/cygwin.py
===================================================================
--- tools/rosdep/src/rosdep/cygwin.py    (revision 12349)
+++ tools/rosdep/src/rosdep/cygwin.py    (working copy)
@@ -51,6 +51,6 @@
 ###### END Cygwin SPECIALIZATION ########################


 if __name__ == '__main__':
-    print "cygwin installed?", Cygwin().check_presence()
-    print "test port_detect(true)", port_detect('cygwin');
-    print "version", Cygwin().get_version()
+    print("cygwin installed?", Cygwin().check_presence())
+    print("test port_detect(true)", port_detect('cygwin'));
+    print("version", Cygwin().get_version())
Index: tools/rosdep/src/rosdep/main.py
===================================================================
--- tools/rosdep/src/rosdep/main.py    (revision 12349)
+++ tools/rosdep/src/rosdep/main.py    (working copy)
@@ -108,9 +108,9 @@
             rdargs = roslib.packages.list_pkgs()


         (verified_packages, rejected_packages) = roslib.stacks.expand_to_packages(rdargs)
-    
+        
         if len(rejected_packages) > 0:
-            print "Warning: could not identify %s as a package"%rejected_packages
+            print("Warning: could not identify %s as a package"%rejected_packages)
         if len(verified_packages) == 0:
             parser.error("No Valid Packages listed")


@@ -121,60 +121,60 @@
     ### Find all dependencies
     try:
         r = core.Rosdep(verified_packages, robust=options.robust)
-    except roslib.os_detect.OSDetectException, ex:
-        print "rosdep ABORTING.  Failed to detect OS: %s"%ex
+    except roslib.os_detect.OSDetectException as ex:
+        print("rosdep ABORTING.  Failed to detect OS: %s"%ex)
         return 1


-    except roslib.exceptions.ROSLibException, ex:
-        print "rosdep ABORTING: %s"%ex
+    except roslib.exceptions.ROSLibException as ex:
+        print("rosdep ABORTING: %s"%ex)
         return 1


     if options.verbose:
-        print "Detected OS: " + r.osi.get_name()
-        print "Detected Version: " + r.osi.get_version()
+        print("Detected OS: " + r.osi.get_name())
+        print("Detected Version: " + r.osi.get_version())


     try:
         if command == "generate_bash" or command == "satisfy":
-            print r.generate_script(include_duplicates=options.include_duplicates, default_yes=options.default_yes)
+            print(r.generate_script(include_duplicates=options.include_duplicates, default_yes=options.default_yes))
             return 0
         elif command == "install":
             error = r.install(options.include_duplicates, options.default_yes)
             if error:
-                print >> sys.stderr, "rosdep install ERROR:\n%s"%error
+                sys.stderr.write("rosdep install ERROR:\n%s"%error)
                 return 1
             else:
                 return 0
-    except core.RosdepException, e:
-        print >> sys.stderr, "ERROR: %s"%e
+    except core.RosdepException as e:
+        sys.stderr.write("ERROR: %s"%e)
         return 1


     try:
         if command == "depdb":
-            print r.depdb(verified_packages)
+            print(r.depdb(verified_packages))
             return 0


         elif command == "what_needs":
-            print '\n'.join(r.what_needs(rdargs))
+            print('\n'.join(r.what_needs(rdargs)))
             return 0


         elif command == "where_defined":
-            print r.where_defined(rdargs)
+            print(r.where_defined(rdargs))
             return 0


         elif command == "check":
             return_val = 0
             (output, scripts) = r.check()
             if len(rejected_packages) > 0:
-                print >> sys.stderr, "Arguments %s are not packages"%rejected_packages
+                sys.stderr.write("Arguments %s are not packages"%rejected_packages)
                 return_val = 1
             if len(output) != 0:
-                print >> sys.stderr, output
+                sys.stderr.write(output + "\n")
                 return 1
             if len(scripts)>0:
-                print >> sys.stderr, scripts
+                sys.stderr.write(scripts + "\n")
                 # not an error condition


             return return_val
-    except core.RosdepException, e:
-        print >> sys.stderr, str(e)
+    except core.RosdepException as e:
+        sys.stderr.write(str(e) + "\n")
         return 1
Index: bin/rosmake
===================================================================
--- bin/rosmake    (revision 12349)
+++ bin/rosmake    (working copy)
@@ -29,8 +29,8 @@



# Author Tully
-from __future__ import with_statement

+
 import os
 import sys
 import subprocess
@@ -43,11 +43,11 @@
     #cmd = ["make", "-C", os.path.join(os.environ["ROS_ROOT"], "tools/rospack")] Doesn't work with cmake 2.6, will trigger rebuilds due to different paths.  Fixed in 2.8.
     cmd = ["bash", "-c", "cd %s && make"%(os.path.join(os.environ["ROS_ROOT"], "tools/rospack"))]
     if subprocess.call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) :
-        print "Rospack failed to build" 
+        print("Rospack failed to build") 
         return False


     if subprocess.call(["which", "rospack"], stdout=subprocess.PIPE, stderr=subprocess.PIPE):
-        print "Rospack not in path.  Please add ROS_ROOT/bin to PATH"
+        print("Rospack not in path.  Please add ROS_ROOT/bin to PATH")
         return False
     return True


@@ -71,6 +71,6 @@
 for t in threading.enumerate():
     if t != threading.currentThread():
         # Join all threads before exiting
-        print "Cleaning up thread", t
+        print("Cleaning up thread", t)
         t.join()
 sys.exit(result)
Index: core/rosbuild/private.cmake
===================================================================
--- core/rosbuild/private.cmake    (revision 12349)
+++ core/rosbuild/private.cmake    (working copy)
@@ -380,7 +380,7 @@


 macro(_rosbuild_get_clock var)
   execute_process(
-    COMMAND python -c "import time; print time.time()"
+    COMMAND python -c "import time; print(time.time())"
     OUTPUT_VARIABLE ${var}
     ERROR_VARIABLE _time_error
     RESULT_VARIABLE _time_failed
@@ -414,7 +414,7 @@
     # Call Python to compare the provided time to the latest mtime on all
     # the files
     execute_process(
-      COMMAND python -c "import os; print 1 if set(${_pylist}) != set(${_cached_pylist}) or ${_t} < max(os.stat(f).st_mtime for f in ${_pylist}) else 0;"
+      COMMAND python -c "import os; print(1 if set(${_pylist}) != set(${_cached_pylist}) or ${_t} < max(os.stat(f).st_mtime for f in ${_pylist}) else 0);"
       OUTPUT_VARIABLE ${var}
       ERROR_VARIABLE _mtime_error
       RESULT_VARIABLE _mtime_failed
Index: core/roslib/src/ros/__init__.py
===================================================================
--- core/roslib/src/ros/__init__.py    (revision 12349)
+++ core/roslib/src/ros/__init__.py    (working copy)
@@ -52,7 +52,7 @@
             import roslib.packages
             try:
                 roslib.load_manifest(name.split('.')[0])
-            except roslib.packages.InvalidROSPkgException, e:
+            except roslib.packages.InvalidROSPkgException as e:
                 raise ImportError("Cannot import module '%s': \n%s"%(name, str(e)))
             return __import__(name)


Index: core/roslib/src/roslib/substitution_args.py
===================================================================
--- core/roslib/src/roslib/substitution_args.py    (revision 12349)
+++ core/roslib/src/roslib/substitution_args.py    (working copy)
@@ -38,8 +38,12 @@
 """


import os
-import cStringIO

+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x
+
 import roslib.exceptions
 import roslib.names
 import roslib.packages
@@ -66,7 +70,7 @@
         raise SubstitutionException("$(env var) command only accepts one argument [%s]"%a)
     try:
         return resolved.replace("$(%s)"%a, os.environ[args[0]])
-    except KeyError, e:
+    except KeyError as e:
         raise SubstitutionException("environment variable %s is not set"%str(e))


 def _optenv(resolved, a, args, context):
@@ -224,7 +228,7 @@
     @return: list of arguments
     @rtype: [str]
     """
-    buff = cStringIO.StringIO()
+    buff = StringIO()
     args = []
     state = _OUT
     for c in arg_str:
Index: core/roslib/src/roslib/stacks.py
===================================================================
--- core/roslib/src/roslib/stacks.py    (revision 12349)
+++ core/roslib/src/roslib/stacks.py    (working copy)
@@ -147,8 +147,10 @@
         except KeyError:
             pass
     _update_stack_cache() #update cache
-    val = _dir_cache.get(stack, None)
-    if val is None:
+
+    try:
+        val = _dir_cache[stack]
+    except KeyError:
         raise InvalidROSStackException("Cannot location installation of stack %s. ROS_ROOT[%s] ROS_PACKAGE_PATH[%s]"%(stack, env[ROS_ROOT], env.get(ROS_PACKAGE_PATH, '')))
     return val


@@ -179,7 +181,7 @@
     if os.path.exists(os.path.join(ros_root, 'stack.xml')):
         _dir_cache['ros'] = ros_root
         pkg_dirs.remove(ros_root)
-
+    
     # pass in accumulated stacks list to each call. This ensures
     # precedence (i.e. that stacks first on pkg_dirs path win). 
     stacks = []
@@ -198,7 +200,7 @@
     @rtype: [str]
     """
     _update_stack_cache()
-    return _dir_cache.keys()
+    return list(_dir_cache.keys())


 def list_stacks_by_path(path, stacks=None, cache=None):
     """
@@ -272,7 +274,7 @@
         if not n in package_list:
             try:
                 valid.extend(roslib.stacks.packages_of(n))
-            except roslib.stacks.InvalidROSStackException, e:
+            except roslib.stacks.InvalidROSStackException as e:
                 invalid.append(n)
         else:
             valid.append(n)
Index: core/roslib/src/roslib/network.py
===================================================================
--- core/roslib/src/roslib/network.py    (revision 12349)
+++ core/roslib/src/roslib/network.py    (working copy)
@@ -45,12 +45,15 @@


import os
import socket
-import string
import struct
import sys
import platform
-import urlparse

+try:
+    import urllib.parse as urlparse
+except ImportError:
+    import urlparse
+
 import roslib.exceptions
 import roslib.rosenv 


@@ -97,7 +100,7 @@
         raise ValueError('not a valid URL')
     if ':' in p[1]:
         hostname, port = p[1].split(':')
-        port = string.atoi(port)
+        port = int(port)
     else: 
         hostname, port = p[1], 80
     return hostname, port
@@ -384,7 +387,7 @@
     @return: header encoded as byte string
     @rtype: str
     """    
-    fields = ["%s=%s"%(k,v) for k,v in header.iteritems()]
+    fields = ["%s=%s"%(k,v) for k,v in header.items()]
     s = ''.join(["%s%s"%(struct.pack('<I', len(f)), f) for f in fields])
     return struct.pack('<I', len(s)) + s


Index: core/roslib/src/roslib/gentools.py
===================================================================
--- core/roslib/src/roslib/gentools.py    (revision 12349)
+++ core/roslib/src/roslib/gentools.py    (working copy)
@@ -44,8 +44,13 @@
 # generator library is rospy.genpy.


import sys
-import cStringIO

+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x
+
+
 import roslib.msgs 
 import roslib.names 
 import roslib.packages 
@@ -101,7 +106,7 @@
     # #1554: need to suppress computation of files in dynamic generation case
     compute_files = 'files' in get_deps_dict


-    buff = cStringIO.StringIO()    
+    buff = StringIO()    


     for c in spec.constants:
         buff.write("%s %s=%s\n"%(c.type, c.name, c.val_text))
@@ -218,7 +223,7 @@
     @return: concatenated text for msg/srv file and embedded msg/srv types.
     @rtype:  str
     """
-    buff = cStringIO.StringIO()
+    buff = StringIO()
     sep = '='*80+'\n'


     # write the text of the top-level type
Index: core/roslib/src/roslib/stack_manifest.py
===================================================================
--- core/roslib/src/roslib/stack_manifest.py    (revision 12349)
+++ core/roslib/src/roslib/stack_manifest.py    (working copy)
@@ -82,7 +82,7 @@
 Stack '%(stack_dir)s' is improperly configured: no manifest file is present.
 """%locals())
         return p
-    except roslib.stacks.InvalidROSStackException, e:
+    except roslib.stacks.InvalidROSStackException as e:
         if required:
             raise


Index: core/roslib/src/roslib/srvs.py
===================================================================
--- core/roslib/src/roslib/srvs.py    (revision 12349)
+++ core/roslib/src/roslib/srvs.py    (working copy)
@@ -39,8 +39,12 @@


import os
import re
-import cStringIO

+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x
+
 import roslib.exceptions
 import roslib.msgs
 import roslib.names
@@ -136,9 +140,9 @@
         try: 
             spec = load_from_file(srv_file(package, t), package)
             specs.append(spec)
-        except Exception, e:
+        except Exception as e:
             failures.append(t)
-            print "ERROR: unable to load %s"%t
+            print("ERROR: unable to load %s"%t)
     return specs, failures


 ##
@@ -148,8 +152,8 @@
 #  @return roslib.MsgSpec: Message type name and message specification
 #  @throws roslib.MsgSpecException: if syntax errors or other problems are detected in file
 def load_from_string(text, package_context='', full_name='', short_name=''):
-    text_in  = cStringIO.StringIO()
-    text_out = cStringIO.StringIO()
+    text_in  = StringIO()
+    text_out = StringIO()
     accum = text_in
     for l in text.split('\n'):
         l = l.split(COMMENTCHAR)[0].strip() #strip comments        
@@ -172,9 +176,9 @@
 def load_from_file(file, package_context=''):
     if VERBOSE:
         if package_context:
-            print "Load spec from", file, "into namespace [%s]"%package_context
+            print("Load spec from", file, "into namespace [%s]"%package_context)
         else:
-            print "Load spec from", file            
+            print("Load spec from", file)            
     fileName = os.path.basename(file)
     type_ = fileName[:-len(EXT)]
     base_type_ = type_
Index: core/roslib/src/roslib/manifestlib.py
===================================================================
--- core/roslib/src/roslib/manifestlib.py    (revision 12349)
+++ core/roslib/src/roslib/manifestlib.py    (working copy)
@@ -54,10 +54,18 @@


class ManifestException(roslib.exceptions.ROSLibException): pass

+def isstring(s):
+    """Small helper version to check an object is a string in a way that works
+    for both Python 2 and 3
+    """
+    try:
+        return isinstance(s, basestring)
+    except NameError:
+        return isinstance(s, str)
+
 # TODO: this is all needlessly complicated in and indirect. Now that
 # we are more commited to our manifest spec, this can be more direct
 # (and unit tested)
-
 def check_optional(name, allowXHTML=False):
     """
     Validator for optional elements.
@@ -81,7 +89,7 @@
     def check(n, filename):
         n = n.getElementsByTagName(name)
         if not n:
-            print >> sys.stderr, "Invalid manifest file[%s]: missing required '%s' element"%(filename, name)
+            sys.stderr.write("Invalid manifest file[%s]: missing required '%s' element\n"%(filename, name))
             return ''
         if len(n) != 1:
             raise ManifestException("Invalid manifest file: must have only one '%s' element"%name)
@@ -99,7 +107,7 @@
         platforms = [e for e in n.getElementsByTagName(name)]
         try:
             vals = [(p.attributes['os'].value, p.attributes['version'].value, p.getAttribute('notes')) for p in platforms]
-        except KeyError, e:
+        except KeyError as e:
             raise ManifestException("<platform> tag is missing required '%s' attribute"%str(e))
         return [Platform(*v) for v in vals]
     return check
@@ -139,7 +147,7 @@


 def _attrs(node):
     attrs = {}
-    for k in node.attributes.keys(): 
+    for k in list(node.attributes.keys()): 
         attrs[k] = node.attributes.get(k).value
     return attrs


@@ -211,7 +219,7 @@
         @return: export instance represented as manifest XML
         @rtype: str
         """        
-        attrs = ' '.join([' %s="%s"'%(k,v) for k,v in self.attrs.iteritems()])
+        attrs = ' '.join([' %s="%s"'%(k,v) for k,v in self.attrs.items()])
         if self.str:
             return '<%s%s>%s</%s>'%(self.tag, attrs, self.str, self.tag)
         else:
@@ -233,11 +241,11 @@
         @param notes: (optional) notes about platform support
         @type  notes: str
         """
-        if not os or not isinstance(os, basestring):
+        if not os or not isstring(os):
             raise ValueError("bad 'os' attribute")
-        if not version or not isinstance(version, basestring):
+        if not version or not isstring(version):
             raise ValueError("bad 'version' attribute")
-        if notes and not isinstance(notes, basestring):
+        if notes and not isstring(notes):
             raise ValueError("bad 'notes' attribute")            
         self.os = os
         self.version = version
@@ -276,7 +284,7 @@
         @param package: package name. must be non-empty
         @type  package: str
         """
-        if not package or not isinstance(package, basestring):
+        if not package or not isstring(package):
             raise ValueError("bad 'package' attribute")
         self.package = package
     def __str__(self):
@@ -305,7 +313,7 @@
         @param stack: stack name. must be non-empty
         @type  stack: str
         """
-        if not stack or not isinstance(stack, basestring):
+        if not stack or not isstring(stack):
             raise ValueError("bad 'stack' attribute")
         self.stack = stack
         self.annotation = None
@@ -340,7 +348,7 @@
         @param name: dependency name. Must be non-empty.
         @type  name: str
         """
-        if not name or not isinstance(name, basestring):
+        if not name or not isstring(name):
             raise ValueError("bad 'name' attribute")
         self.name = name
     def xml(self):
@@ -363,9 +371,9 @@
         @param url: URL associated with version control. must be non empty
         @type  url: str
         """
-        if not type_ or not isinstance(type_, basestring):
+        if not type_ or not isstring(type_):
             raise ValueError("bad 'type' attribute")
-        if not url is None and not isinstance(url, basestring):
+        if not url is None and not isstring(url):
             raise ValueError("bad 'url' attribute")
         self.type = type_
         self.url = url
@@ -441,7 +449,7 @@
             review = '  <review status="%s" notes="%s" />'%(self.status, self.notes)



-        fields = filter(lambda x: x, [desc, author, license, review, url, logo, depends, rosdeps, platforms, exports, versioncontrol])
+        fields = [x for x in [desc, author, license, review, url, logo, depends, rosdeps, platforms, exports, versioncontrol] if x]
         return "<%s>\n"%self._type + "\n".join(fields) + "\n</%s>"%self._type


 def _get_text(nodes):
@@ -471,7 +479,7 @@
         f.close()
     try:
         return parse(m, text, file)
-    except ManifestException, e:
+    except ManifestException as e:
         raise ManifestException("Invalid manifest file [%s]: %s"%(os.path.abspath(file), e))


 def parse(m, string, filename='string'):
@@ -486,7 +494,7 @@
     """
     try:
         d = dom.parseString(string)
-    except Exception, e:
+    except Exception as e:
         raise ManifestException("invalid XML: %s"%e)
     p = d.getElementsByTagName(m._type)
     if len(p) != 1:
Index: core/roslib/src/roslib/msg/_Clock.py
===================================================================
--- core/roslib/src/roslib/msg/_Clock.py    (revision 12349)
+++ core/roslib/src/roslib/msg/_Clock.py    (working copy)
@@ -54,8 +54,8 @@
     try:
       _x = self
       buff.write(_struct_2I.pack(_x.clock.secs, _x.clock.nsecs))
-    except struct.error, se: self._check_types(se)
-    except TypeError, te: self._check_types(te)
+    except struct.error as se: self._check_types(se)
+    except TypeError as te: self._check_types(te)


   def deserialize(self, str):
     """
@@ -73,7 +73,7 @@
       (_x.clock.secs, _x.clock.nsecs,) = _struct_2I.unpack(str[start:end])
       self.clock.canon()
       return self
-    except struct.error, e:
+    except struct.error as e:
       raise roslib.message.DeserializationError(e) #most likely buffer underfill



@@ -88,8 +88,8 @@
     try:
       _x = self
       buff.write(_struct_2I.pack(_x.clock.secs, _x.clock.nsecs))
-    except struct.error, se: self._check_types(se)
-    except TypeError, te: self._check_types(te)
+    except struct.error as se: self._check_types(se)
+    except TypeError as te: self._check_types(te)


   def deserialize_numpy(self, str, numpy):
     """
@@ -109,7 +109,7 @@
       (_x.clock.secs, _x.clock.nsecs,) = _struct_2I.unpack(str[start:end])
       self.clock.canon()
       return self
-    except struct.error, e:
+    except struct.error as e:
       raise roslib.message.DeserializationError(e) #most likely buffer underfill


 _struct_I = roslib.message.struct_I
Index: core/roslib/src/roslib/msg/__init__.py
===================================================================
--- core/roslib/src/roslib/msg/__init__.py    (revision 12349)
+++ core/roslib/src/roslib/msg/__init__.py    (working copy)
@@ -1,3 +1,3 @@
-from _Header import *
-from _Log import *
-from _Clock import *
+from ._Header import *
+from ._Log import *
+from ._Clock import *
Index: core/roslib/src/roslib/msg/_Log.py
===================================================================
--- core/roslib/src/roslib/msg/_Log.py    (revision 12349)
+++ core/roslib/src/roslib/msg/_Log.py    (working copy)
@@ -137,8 +137,8 @@
       for val1 in self.topics:
         length = len(val1)
         buff.write(struct.pack('<I%ss'%length, length, val1))
-    except struct.error, se: self._check_types(se)
-    except TypeError, te: self._check_types(te)
+    except struct.error as se: self._check_types(se)
+    except TypeError as te: self._check_types(te)


   def deserialize(self, str):
     """
@@ -194,7 +194,7 @@
       end += 4
       (length,) = _struct_I.unpack(str[start:end])
       self.topics = []
-      for i in xrange(0, length):
+      for i in range(0, length):
         start = end
         end += 4
         (length,) = _struct_I.unpack(str[start:end])
@@ -203,7 +203,7 @@
         val1 = str[start:end]
         self.topics.append(val1)
       return self
-    except struct.error, e:
+    except struct.error as e:
       raise roslib.message.DeserializationError(e) #most likely buffer underfill



@@ -240,8 +240,8 @@
       for val1 in self.topics:
         length = len(val1)
         buff.write(struct.pack('<I%ss'%length, length, val1))
-    except struct.error, se: self._check_types(se)
-    except TypeError, te: self._check_types(te)
+    except struct.error as se: self._check_types(se)
+    except TypeError as te: self._check_types(te)


   def deserialize_numpy(self, str, numpy):
     """
@@ -299,7 +299,7 @@
       end += 4
       (length,) = _struct_I.unpack(str[start:end])
       self.topics = []
-      for i in xrange(0, length):
+      for i in range(0, length):
         start = end
         end += 4
         (length,) = _struct_I.unpack(str[start:end])
@@ -308,7 +308,7 @@
         val1 = str[start:end]
         self.topics.append(val1)
       return self
-    except struct.error, e:
+    except struct.error as e:
       raise roslib.message.DeserializationError(e) #most likely buffer underfill


 _struct_I = roslib.message.struct_I
Index: core/roslib/src/roslib/msg/_Header.py
===================================================================
--- core/roslib/src/roslib/msg/_Header.py    (revision 12349)
+++ core/roslib/src/roslib/msg/_Header.py    (working copy)
@@ -74,8 +74,10 @@
       _x = self.frame_id
       length = len(_x)
       buff.write(struct.pack('<I%ss'%length, length, _x))
-    except struct.error, se: self._check_types(se)
-    except TypeError, te: self._check_types(te)
+    except struct.error as se:
+        self._check_types(se)
+    except TypeError as te: 
+        self._check_types(te)


   def deserialize(self, str):
     """
@@ -99,7 +101,7 @@
       self.frame_id = str[start:end]
       self.stamp.canon()
       return self
-    except struct.error, e:
+    except struct.error as e:
       raise roslib.message.DeserializationError(e) #most likely buffer underfill



@@ -117,8 +119,10 @@
       _x = self.frame_id
       length = len(_x)
       buff.write(struct.pack('<I%ss'%length, length, _x))
-    except struct.error, se: self._check_types(se)
-    except TypeError, te: self._check_types(te)
+    except struct.error as se:
+        self._check_types(se)
+    except TypeError as te:
+        self._check_types(te)


   def deserialize_numpy(self, str, numpy):
     """
@@ -144,7 +148,7 @@
       self.frame_id = str[start:end]
       self.stamp.canon()
       return self
-    except struct.error, e:
+    except struct.error as e:
       raise roslib.message.DeserializationError(e) #most likely buffer underfill


 _struct_I = roslib.message.struct_I
Index: core/roslib/src/roslib/launcher.py
===================================================================
--- core/roslib/src/roslib/launcher.py    (revision 12349)
+++ core/roslib/src/roslib/launcher.py    (working copy)
@@ -89,7 +89,7 @@
                 paths.append(e.replace('${prefix}', pkg_dir))
     else:
         dirs = [os.path.join(pkg_dir, d) for d in ['src', 'lib']]
-        paths.extend(filter(os.path.isdir, dirs))
+        paths.extend(list(filter(os.path.isdir, dirs)))


 def _generate_python_path(pkg, depends, env=os.environ):
     """
@@ -120,7 +120,7 @@
                 continue 
             try: #add sub-dependencies to paths and depends
                 paths.extend(_generate_python_path(d.package, depends, env))
-            except roslib.packages.InvalidROSPkgException, e:
+            except roslib.packages.InvalidROSPkgException as e:
                 # translate error message to give more context
                 raise roslib.packages.InvalidROSPkgException("While loading package '%s': %s"%(d.package, str(e)))
             except:
Index: core/roslib/src/roslib/scriptutil.py
===================================================================
--- core/roslib/src/roslib/scriptutil.py    (revision 12349)
+++ core/roslib/src/roslib/scriptutil.py    (working copy)
@@ -128,14 +128,18 @@
     @return: XML-RPC proxy to ROS master
     @rtype: xmlrpclib.ServerProxy
     """
-    import xmlrpclib
+    try:
+        import xmlrpc.client as xmlrpcclient  #Python 3.x
+    except ImportError:
+        import xmlrpclib as xmlrpcclient #Python 2.x
+    
     # #1730 validate URL for better error messages
     uri = roslib.rosenv.get_master_uri()
     try:
         roslib.network.parse_http_host_and_port(uri)
     except ValueError:
         raise roslib.exceptions.ROSLibException("invalid master URI: %s"%uri)
-    return xmlrpclib.ServerProxy(uri)
+    return xmlrpcclient.ServerProxy(uri)



 def get_param_server():
@@ -194,7 +198,7 @@
     # Pretty-print a string version of the commands
     def quote(s):
         return '"%s"'%s if ' ' in s else s
-    print "Okay to execute:\n\n%s\n(y/n)?"%('\n'.join([' '.join([quote(s) for s in c]) for c in cmds]))
+    print("Okay to execute:\n\n%s\n(y/n)?"%('\n'.join([' '.join([quote(s) for s in c]) for c in cmds])))
     while 1:
         input = sys.stdin.readline().strip()
         if input in ['y', 'n']:
Index: core/roslib/src/roslib/rospack.py
===================================================================
--- core/roslib/src/roslib/rospack.py    (revision 12349)
+++ core/roslib/src/roslib/rospack.py    (working copy)
@@ -49,7 +49,7 @@
     @raise roslib.exceptions.ROSLibException: if rospack command fails
     """
     rospack_bin = os.path.join(roslib.rosenv.get_ros_root(), 'bin', 'rospack')
-    val = (subprocess.Popen([rospack_bin] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] or '').strip()
+    val = (bytes.decode(subprocess.Popen([rospack_bin] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]) or '').strip()
     if val.startswith('rospack:'): #rospack error message
         raise roslib.exceptions.ROSLibException(val)
     return val
@@ -110,7 +110,7 @@
     @raise roslib.exceptions.ROSLibException: if rosstack command fails
     """
     rosstack_bin = os.path.join(roslib.rosenv.get_ros_root(), 'bin', 'rosstack')
-    val = (subprocess.Popen([rosstack_bin] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] or '').strip()
+    val = (bytes.decode(subprocess.Popen([rosstack_bin] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]) or '').strip()
     if val.startswith('rosstack:'): #rospack error message
         raise roslib.exceptions.ROSLibException(val)
     return val
Index: core/roslib/src/roslib/names.py
===================================================================
--- core/roslib/src/roslib/names.py    (revision 12349)
+++ core/roslib/src/roslib/names.py    (working copy)
@@ -55,6 +55,15 @@
 REMAP = ":="
 ANYTYPE = '*'


+def isstring(s):
+    """Small helper version to check an object is a string in a way that works
+    for both Python 2 and 3
+    """
+    try:
+        return isinstance(s, basestring) #Python 2.x
+    except NameError:
+        return isinstance(s, str) #Python 3.x
+
 def get_ros_namespace(env=None, argv=None):
     """
     @param env: environment dictionary (defaults to os.environ)
@@ -142,7 +151,7 @@
     "map name to its namespace"
     if name is None: 
         raise ValueError('name')
-    if not isinstance(name, basestring):
+    if not isstring(name):
         raise TypeError('name')
     if not name:
         return SEP
@@ -194,7 +203,7 @@
                     else:
                         mappings[src] = dst
             except:
-                print >> sys.stderr, "ERROR: Invalid remapping argument '%s'"%arg
+                sys.stderr.write("ERROR: Invalid remapping argument '%s'\n"%arg)
     return mappings


#######################################################################
@@ -268,7 +277,7 @@

 def _is_safe_name(name, type_name):
     #windows long-file name length is 255
-    if not isinstance(name, basestring) or not name or len(name) > 255:
+    if not isstring(name) or not name or len(name) > 255:
         return False
     return is_legal_resource_name(name)


@@ -289,7 +298,7 @@
     @type  name: str
     """
     # resource names can be unicode due to filesystem
-    if name is None or not isinstance(name, basestring):
+    if name is None or not isstring(name):
         return False
     m = RESOURCE_NAME_LEGAL_CHARS_P.match(name)
     # '//' check makes sure there isn't double-slashes
@@ -308,7 +317,7 @@
     @type  name: str
     """    
     # should we enforce unicode checks?
-    if name is None or not isinstance(name, basestring):
+    if name is None or not isstring(name):
         return False
     # empty string is a legal name as it resolves to namespace
     if name == '':
@@ -322,7 +331,7 @@
     Validates that name is a legal base name for a graph resource. A base name has
     no namespace context, e.g. "node_name".
     """
-    if name is None or not isinstance(name, basestring):
+    if name is None or not isstring(name):
         return False
     m = BASE_NAME_LEGAL_CHARS_P.match(name)
     return m is not None and m.group(0) == name
@@ -334,7 +343,7 @@
     no package context, e.g. "String".
     """
     # resource names can be unicode due to filesystem
-    if name is None or not isinstance(name, basestring):
+    if name is None or not isstring(name):
         return False
     m = BASE_NAME_LEGAL_CHARS_P.match(name)
     return m is not None and m.group(0) == name
@@ -395,7 +404,7 @@
     @type  id: str
     """
     import socket, random
-    name = "%s_%s_%s_%s"%(id, socket.gethostname(), os.getpid(), random.randint(0, sys.maxint))
+    name = "%s_%s_%s_%s"%(id, socket.gethostname(), os.getpid(), random.randint(0, sys.maxsize))
     # RFC 952 allows hyphens, IP addrs can have '.'s, both
     # of which are illegal for ROS names. For good
     # measure, screen ipv6 ':'. 
Index: core/roslib/src/roslib/xmlrpc.py
===================================================================
--- core/roslib/src/roslib/xmlrpc.py    (revision 12349)
+++ core/roslib/src/roslib/xmlrpc.py    (working copy)
@@ -43,20 +43,43 @@
 import logging
 import socket
 import string
-import thread
+
+try:
+    import _thread
+except ImportError:
+    import thread as _thread
+
 import traceback
-from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
-import SocketServer


+try:
+    from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler #Python 3.x
+except ImportError:
+    from SimpleXMLRPCServer import SimpleXMLRPCServer #Python 2.x
+    from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler #Python 2.x
+
+try:
+    import socketserver
+except ImportError:
+    import SocketServer as socketserver
+
 import roslib.network
 import roslib.exceptions


+def isstring(s):
+    """Small helper version to check an object is a string in a way that works
+    for both Python 2 and 3
+    """
+    try:
+        return isinstance(s, basestring)
+    except NameError:
+        return isinstance(s, str)
+
 class SilenceableXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
     def log_message(self, format, *args):
         if DEBUG:
             SimpleXMLRPCRequestHandler.log_message(self, format, *args)


-class ThreadingXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
+class ThreadingXMLRPCServer(socketserver.ThreadingMixIn, SimpleXMLRPCServer):
     """
     Adds ThreadingMixin to SimpleXMLRPCServer to support multiple concurrent
     requests via threading. Also makes logging toggleable.
@@ -80,7 +103,7 @@
             if logger:
                 logger.error(traceback.format_exc())


-class ForkingXMLRPCServer(SocketServer.ForkingMixIn, SimpleXMLRPCServer):
+class ForkingXMLRPCServer(socketserver.ForkingMixIn, SimpleXMLRPCServer):
     """
     Adds ThreadingMixin to SimpleXMLRPCServer to support multiple concurrent
     requests via forking. Also makes logging toggleable.      
@@ -126,8 +149,8 @@
         self.handler = rpc_handler
         self.uri = None # initialize the property now so it can be tested against, will be filled in later
         self.server = None
-        if port and isinstance(port, basestring):
-            port = string.atoi(port)
+        if port and isstring(port):
+            port = int(port)
         self.port = port
         self.is_shutdown = False
         self.on_run_error = on_run_error
@@ -153,7 +176,7 @@
         """
         Initiate a thread to run the XML RPC server. Uses thread.start_new_thread.
         """
-        thread.start_new_thread(self.run, ())
+        _thread.start_new_thread(self.run, ())


     def set_uri(self, uri):
         """
@@ -167,7 +190,7 @@
     def run(self):
         try:
             self._run()
-        except Exception, e:
+        except Exception as e:
             if self.on_run_error is not None:
                self.on_run_error(e)
             else:
@@ -219,13 +242,14 @@
             self.server.register_multicall_functions()
             self.server.register_instance(self.handler)


-        except socket.error, (n, errstr):
+        except socket.error as e:
+            (n, errstr) = e
             if n == 98:
                 msg = "ERROR: Unable to start XML-RPC server, port %s is already in use"%self.port
             else:
                 msg = "ERROR: Unable to start XML-RPC server: %s"%errstr                
             logger.error(msg)
-            print msg
+            print(msg)
             raise #let higher level catch this


         if self.handler is not None:
Index: core/roslib/src/roslib/manifest.py
===================================================================
--- core/roslib/src/roslib/manifest.py    (revision 12349)
+++ core/roslib/src/roslib/manifest.py    (working copy)
@@ -93,7 +93,7 @@
 Package '%(package_dir)s' is improperly configured: no manifest file is present.
 """%locals())
         return p
-    except roslib.packages.InvalidROSPkgException, e:
+    except roslib.packages.InvalidROSPkgException as e:
         if required:
             raise


Index: core/roslib/src/roslib/os_detect.py
===================================================================
--- core/roslib/src/roslib/os_detect.py    (revision 12349)
+++ core/roslib/src/roslib/os_detect.py    (working copy)
@@ -36,8 +36,8 @@
 command-line tool.
 """


-from __future__ import with_statement

+
 import roslib.exceptions
 import roslib.rospack
 import roslib.stacks
@@ -192,7 +192,7 @@
                 if os_list[0] == "Fedora" and os_list[1] == "release":
                     return os_list[2]
         except:
-            print "Fedora failed to get version"
+            print("Fedora failed to get version")
             return False


         return False
@@ -228,7 +228,7 @@
                 if os_list and os_list[2] == "Enterprise":
                     return os_list[6]
         except:
-            print "Rhel failed to get version"
+            print("Rhel failed to get version")
             return False


         return False
@@ -290,7 +290,7 @@
                 if os_list[0] == "Linux" and os_list[1] == "Arch":
                     return os_list[2]
         except:
-            print "Arch failed to get version"
+            print("Arch failed to get version")
             return False


         return False
@@ -349,7 +349,7 @@
                 if os_list[0] == "Gentoo" and os_list[1] == "Base":
                     return os_list[4]
         except:
-            print >> sys.stderr, "Gentoo failed to get version"
+            sys.stderr.write("Gentoo failed to get version\n")
             return False


         return False
@@ -388,7 +388,7 @@
             else:
                return False
         except:
-            print >> sys.stderr, "FreeBSD failed to get version"
+            sys.stderr.write("FreeBSD failed to get version\n")
             return False


         return False
@@ -407,7 +407,7 @@
     def check_presence(self):
         try:
             (self._os_name, self._os_version) = os.environ["ROS_OS_OVERRIDE"].split(':')
-            print >> sys.stderr, "Using environment variable ROS_OS_OVERRIDE name = %s version = %s"%(self._os_name, self._os_version)
+            sys.stderr.write("Using environment variable ROS_OS_OVERRIDE name = %s version = %s\n"%(self._os_name, self._os_version))
             return True
         except:
             return False
Index: core/roslib/src/roslib/msgs.py
===================================================================
--- core/roslib/src/roslib/msgs.py    (revision 12349)
+++ core/roslib/src/roslib/msgs.py    (working copy)
@@ -38,7 +38,11 @@
 Implements: U{http://ros.org/wiki/msg}
 """


-import cStringIO
+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x
+
 import os
 import itertools
 import sys
@@ -234,7 +238,7 @@
     @rtype: str
     """
     if buff is None:
-        buff = cStringIO.StringIO()
+        buff = StringIO()
     for c in spec.constants:
         buff.write("%s%s %s=%s\n"%(indent, c.type, c.name, c.val_text))
     for type_, name in zip(spec.types, spec.names):
@@ -310,7 +314,7 @@
         @return: zip list of types and names (e.g. [('int32', 'x'), ('int32', 'y')]
         @rtype: [(str,str),]
         """
-        return zip(self.types, self.names)
+        return list(zip(self.types, self.names))


     def parsed_fields(self):
         """
@@ -373,7 +377,7 @@


     header = os.path.join(roslib_dir, roslib.packages.MSG_DIR, fname)
     if not os.path.isfile(header):
-        print >> sys.stderr, "ERROR: cannot locate %s. Excepted to find it at '%s'"%(fname, header)
+        sys.stderr.write("ERROR: cannot locate %s. Excepted to find it at '%s'\n"%(fname, header))
         return False


     # register Header under both contexted and de-contexted name
@@ -382,7 +386,7 @@
     register('std_msgs/'+HEADER, spec)    
     # backwards compat, REP 100
     register('roslib/'+HEADER, spec)    
-    for k, spec in EXTENDED_BUILTINS.iteritems():
+    for k, spec in EXTENDED_BUILTINS.items():
         register(k, spec)


     _initialized = True
@@ -440,9 +444,9 @@
         try: 
             typespec = load_from_file(msg_file(package, t), package)
             specs.append(typespec)
-        except Exception, e:
+        except Exception as e:
             failures.append(t)
-            print "ERROR: unable to load %s"%t
+            print("ERROR: unable to load %s"%t)
     return specs, failures


 def load_package_dependencies(package, load_recursive=False):
@@ -457,7 +461,7 @@
     global _loaded_packages
     _init()    
     if VERBOSE:
-        print "Load dependencies for package", package
+        print("Load dependencies for package", package)


     if not load_recursive:
         manifest_file = roslib.manifest.manifest_file(package, True)
@@ -470,7 +474,7 @@
     failures = []
     for d in depends:
         if VERBOSE:
-            print "Load dependency", d
+            print("Load dependency", d)
         #check if already loaded
         # - we are dependent on manifest.getAll returning first-order dependencies first
         if d in _loaded_packages or d == package:
@@ -495,19 +499,19 @@
     global _loaded_packages
     _init()    
     if VERBOSE:
-        print "Load package", package
+        print("Load package", package)


     #check if already loaded
     # - we are dependent on manifest.getAll returning first-order dependencies first
     if package in _loaded_packages:
         if VERBOSE:
-            print "Package %s is already loaded"%package
+            print("Package %s is already loaded"%package)
         return


     _loaded_packages.append(package)
     specs, failed = get_pkg_msg_specs(package)
     if VERBOSE:
-        print "Package contains the following messages: %s"%specs
+        print("Package contains the following messages: %s"%specs)
     for key, spec in specs:
         #register spec under both local and fully-qualified key
         register(key, spec)
@@ -588,7 +592,7 @@
         l = orig_line.split(COMMENTCHAR)[0].strip() #strip comments
         if not l:
             continue #ignore empty lines
-        splits = filter(lambda s: s, [x.strip() for x in l.split(" ")]) #split type/name, filter out empties
+        splits = [s for s in [x.strip() for x in l.split(" ")] if s] #split type/name, filter out empties
         type_ = splits[0]
         if not is_valid_msg_type(type_):
             raise MsgSpecException("%s is not a legal message type"%type_)
@@ -608,7 +612,7 @@
                 val = splits[1]
             try:
                 val_converted  = _convert_val(type_, val)
-            except Exception, e:
+            except Exception as e:
                 raise MsgSpecException("Invalid declaration: %s"%e)
             constants.append(Constant(type_, name, val_converted, val.strip()))
         else:
@@ -640,9 +644,9 @@
     """
     if VERBOSE:
         if package_context:
-            print "Load spec from", file_path, "into package [%s]"%package_context
+            print("Load spec from", file_path, "into package [%s]"%package_context)
         else:
-            print "Load spec from", file_path
+            print("Load spec from", file_path)


     file_name = os.path.basename(file_path)
     type_ = file_name[:-len(EXT)]
@@ -660,7 +664,7 @@
         try:
             text = f.read()
             return (type_, load_from_string(text, package_context, type_, base_type_))
-        except MsgSpecException, e:
+        except MsgSpecException as e:
             raise MsgSpecException('%s: %s'%(file_name, e))
     finally:
         f.close()
@@ -725,7 +729,7 @@
     registered. NOTE: builtin types are not registered.
     @rtype: bool
     """
-    return REGISTERED_TYPES.has_key(msg_type_name)
+    return msg_type_name in REGISTERED_TYPES


 def get_registered(msg_type_name, default_package=None):
     """
@@ -753,6 +757,6 @@
     @type  msg_spec: L{MsgSpec}
     """
     if VERBOSE:
-        print "Register msg %s"%msg_type_name
+        print("Register msg %s"%msg_type_name)
     REGISTERED_TYPES[msg_type_name] = msg_spec


Index: core/roslib/src/roslib/resources.py
===================================================================
--- core/roslib/src/roslib/resources.py    (revision 12349)
+++ core/roslib/src/roslib/resources.py    (working copy)
@@ -81,8 +81,8 @@
     if include_depends:
         depends = _get_manifest_by_dir(package_dir).depends
         dirs = [roslib.packages.get_pkg_subdir(d.package, subdir, False) for d in depends]
-        dirs = filter(lambda dir: dir and os.path.isdir(dir), dirs)
-        for (dep, dir) in itertools.izip(depends, dirs):
+        dirs = [dir for dir in dirs if dir and os.path.isdir(dir)]
+        for (dep, dir) in zip(depends, dirs):
             resources.extend(\
                 [roslib.names.resource_name(dep.package, f, my_pkg=package) \
                  for f in os.listdir(dir) if rfilter(os.path.join(dir, f))])
Index: core/roslib/src/roslib/roslogging.py
===================================================================
--- core/roslib/src/roslib/roslogging.py    (revision 12349)
+++ core/roslib/src/roslib/roslogging.py    (working copy)
@@ -80,7 +80,7 @@
             makedirs_with_parent_perms(logfile_dir)
         except OSError:
             # cannot print to screen because command-line tools with output use this
-            print >> sys.stderr, "WARNING: cannot create log directory [%s]. Please set %s to a writable location."%(logfile_dir, ROS_LOG_DIR)
+            sys.stderr.write("WARNING: cannot create log directory [%s]. Please set %s to a writable location.\n"%(logfile_dir, ROS_LOG_DIR))
             return None
     elif os.path.isfile(logfile_dir):
         raise roslib.exceptions.ROSLibException("Cannot save log files: file [%s] is in the way"%logfile_dir)
@@ -92,7 +92,7 @@


     if not os.path.isfile(config_file):
         # logging is considered soft-fail
-        print >> sys.stderr, "WARNING: cannot load logging configuration file, logging is disabled"
+        sys.stderr.write("WARNING: cannot load logging configuration file, logging is disabled\n")
         return log_filename


     # pass in log_filename as argument to pylogging.conf
Index: core/roslib/src/roslib/rosenv.py
===================================================================
--- core/roslib/src/roslib/rosenv.py    (revision 12349)
+++ core/roslib/src/roslib/rosenv.py    (working copy)
@@ -80,31 +80,31 @@
         env = os.environ
     p = None
     try:
-        if not env.has_key(ROS_ROOT):
-            raise ROSEnvException, """
+        if ROS_ROOT not in env:
+            raise ROSEnvException("""
 The %(ROS_ROOT)s environment variable has not been set.
 Please set to the location of your ROS installation
 before continuing.
-"""%globals()
+"""%globals())


         p = env[ROS_ROOT]
         #Test:
         # 1. Is a path
         # 2. Is a directory
         if not os.path.exists(p):
-            raise ROSEnvException, """
+            raise ROSEnvException("""
 The %s environment variable has not been set properly:
 %s does not exist.
 Please update your ROS installation before continuing.
-"""%(ROS_ROOT, p)
+"""%(ROS_ROOT, p))
         if not os.path.isdir(p):
-            raise ROSEnvException, """
+            raise ROSEnvException("""
 The %s environment variable has not been set properly:
 %s is not a directory.
 Please update your ROS installation before continuing.
-"""%(ROS_ROOT, p)
+"""%(ROS_ROOT, p))
         return p
-    except Exception, e:
+    except Exception as e:
         if required:
             raise
         return p
@@ -121,7 +121,7 @@
         env = os.environ
     try:
         return env[ROS_PACKAGE_PATH]
-    except KeyError, e:
+    except KeyError as e:
         if required:
             raise ROSEnvException("%s has not been configured"%ROS_PACKAGE_PATH)


@@ -158,7 +158,7 @@
                     raise ROSEnvException("__master remapping argument '%s' improperly specified"%arg)
                 return val
         return env[ROS_MASTER_URI]
-    except KeyError, e:
+    except KeyError as e:
         if required:
             raise ROSEnvException("%s has not been configured"%ROS_MASTER_URI)


Index: core/roslib/src/roslib/packages.py
===================================================================
--- core/roslib/src/roslib/packages.py    (revision 12349)
+++ core/roslib/src/roslib/packages.py    (working copy)
@@ -42,8 +42,8 @@
 in very experimental.
 """


-from __future__ import with_statement

+
 import os
 import sys
 import stat
@@ -220,11 +220,11 @@
         # rospack_cache as it will corrupt list_pkgs() otherwise.
         #_pkg_dir_cache[package] = (pkg_dir, ros_root, ros_package_path)
         return pkg_dir
-    except OSError, e:
+    except OSError as e:
         if required:
             raise InvalidROSPkgException("Environment configuration is invalid: cannot locate rospack (%s)"%e)
         return None
-    except Exception, e:
+    except Exception as e:
         if required:
             raise
         return None
@@ -264,7 +264,7 @@
 Please check permissions and try again.
 """%locals())
         return dir
-    except Exception, e:
+    except Exception as e:
         if required:
             raise
         return None
@@ -399,9 +399,9 @@
             # cache in most optimal way
             cache = _pkg_dir_cache
             if cache:
-                return cache.keys()
+                return list(cache.keys())
             if _update_rospack_cache():
-                return cache.keys()
+                return list(cache.keys())
     else:
         import warnings
         warnings.warn("pkg_dirs argument is deprecated. Please use list_pkgs_by_path() instead", DeprecationWarning, stacklevel=2)
@@ -572,7 +572,7 @@
     manifests = [load_manifest(p) for p in packages]
     import itertools
     map = {}
-    for pkg, m in itertools.izip(packages, manifests):
+    for pkg, m in zip(packages, manifests):
         map[pkg] = [d.name for d in m.rosdeps]
     return map


Index: core/roslib/src/roslib/genpy.py
===================================================================
--- core/roslib/src/roslib/genpy.py    (revision 12349)
+++ core/roslib/src/roslib/genpy.py    (working copy)
@@ -58,7 +58,10 @@
 import traceback
 import struct


-from cStringIO import StringIO
+try:
+    from cStringIO import StringIO # Python 2.x
+except ImportError:
+    from io import StringIO # Python 3.x


 import roslib.exceptions
 import roslib.gentools
@@ -108,7 +111,7 @@
     }


## Simple types are primitives with fixed-serialization length
-SIMPLE_TYPES = SIMPLE_TYPES_DICT.keys()
+SIMPLE_TYPES = list(SIMPLE_TYPES_DICT.keys())

 def is_simple(type_):
     """
@@ -743,7 +746,7 @@


     except MsgGenerationException:
         raise #re-raise
-    except Exception, e:
+    except Exception as e:
         raise MsgGenerationException(e) #wrap


 def complex_serializer_generator(package, type_, name, serialize, is_numpy):
@@ -1179,17 +1182,17 @@
     # types. The types have to be registered globally in order for
     # message generation of dependents to work correctly.
     roslib.msgs.reinit()
-    for t, spec in specs.iteritems():
+    for t, spec in specs.items():
         roslib.msgs.register(t, spec)


     # process actual MsgSpecs: we accumulate them into a single file,
     # rewriting the generated text as needed
     buff = StringIO()
-    for t, spec in specs.iteritems():
+    for t, spec in specs.items():
         pkg, s_type = roslib.names.package_resource_name(t)
         # dynamically generate python message code
         for l in msg_generator(pkg, s_type, spec):
-            l = _gen_dyn_modify_references(l, specs.keys())
+            l = _gen_dyn_modify_references(l, list(specs.keys()))
             buff.write(l + '\n')
     full_text = buff.getvalue()


@@ -1212,7 +1215,7 @@

     # finally, retrieve the message classes from the dynamic module
     messages = {}
-    for t in specs.iterkeys():
+    for t in specs.keys():
         pkg, s_type = roslib.names.package_resource_name(t)
         try:
             messages[t] = getattr(mod, _gen_dyn_name(pkg, s_type))
Index: core/roslib/src/roslib/rostime.py
===================================================================
--- core/roslib/src/roslib/rostime.py    (revision 12349)
+++ core/roslib/src/roslib/rostime.py    (working copy)
@@ -126,7 +126,7 @@
         @return: time as nanoseconds
         @rtype: long
         """
-        return self.secs * long(1e9) + self.nsecs
+        return self.secs * int(1e9) + self.nsecs


     def __hash__(self):
         """
@@ -140,7 +140,7 @@
     def __repr__(self):
         return "rostime.TVal[%d]"%self.to_nsec()


-    def __nonzero__(self):
+    def __bool__(self):
         """
         Check if time value is zero
         """
@@ -418,7 +418,7 @@
         @rtype:  L{Duration}
         """
         t = type(val)
-        if t in (int, long):
+        if t in (int, int):
             return Duration(self.secs * val, self.nsecs * val)
         elif t == float:
             return Duration.from_sec(self.to_sec() * val)
@@ -434,7 +434,7 @@
         @rtype:  L{Duration}
         """
         t = type(val)
-        if t in (int, long):
+        if t in (int, int):
             return Duration(self.secs // val, self.nsecs // val)
         elif t == float:
             return Duration.from_sec(self.to_sec() // val)
@@ -451,7 +451,7 @@
         """
         # unlike __floordiv__, this uses true div for float arg
         t = type(val)
-        if t in (int, long):
+        if t in (int, int):
             return Duration(self.secs // val, self.nsecs // val)
         elif t == float:
             return Duration.from_sec(self.to_sec() / val)
@@ -467,7 +467,7 @@
         @rtype:  L{Duration}
         """
         t = type(val)
-        if t in (int, long):
+        if t in (int, int):
             return Duration(self.secs / val, self.nsecs / val)
         elif t == float:
             return Duration.from_sec(self.to_sec() / val)
Index: core/roslib/src/roslib/params.py
===================================================================
--- core/roslib/src/roslib/params.py    (revision 12349)
+++ core/roslib/src/roslib/params.py    (working copy)
@@ -37,7 +37,7 @@
 """


import sys
-import xmlrpclib
+from . import xmlrpc

 import roslib.rosenv
 from roslib.names import REMAP
@@ -55,8 +55,8 @@
     """    
     try:
         import yaml
-    except ImportError, e:
-        print >> sys.stderr, "Cannot import yaml. Please make sure the pyyaml system dependency is installed"
+    except ImportError as e:
+        sys.stderr.write("Cannot import yaml. Please make sure the pyyaml system dependency is installed\n")
         raise e
     mappings = {}
     for arg in argv:
@@ -67,7 +67,7 @@
                     if len(src) > 1 and src[0] == '_' and src[1] != '_':
                         mappings[src[1:]] = yaml.load(dst)
             except:
-                print >> sys.stderr, "ERROR: Invalid remapping argument '%s'"%arg
+                sys.stderr.write("ERROR: Invalid remapping argument '%s'\n"%arg)
     return mappings


 def get_param(key):
@@ -82,7 +82,7 @@
     """
     global _param_server
     if _param_server is None:
-        _param_server = xmlrpclib.ServerProxy(roslib.rosenv.get_master_uri())
+        _param_server = xmlrpc.client.ServerProxy(roslib.rosenv.get_master_uri())
     code, status, value = _param_server.getParam('/roslib', key)
     if code != 1: #unwrap value with Python semantics
         raise KeyError(key)
Index: core/roslib/src/roslib/message.py
===================================================================
--- core/roslib/src/roslib/message.py    (revision 12349)
+++ core/roslib/src/roslib/message.py    (working copy)
@@ -52,6 +52,15 @@
 # add another import to messages (which incurs higher import cost)
 struct_I = struct.Struct('<I')


+def isstring(s):
+    """Small helper version to check an object is a string in a way that works
+    for both Python 2 and 3
+    """
+    try:
+        return isinstance(s, basestring)
+    except NameError:
+        return isinstance(s, str)
+    
 class ROSMessageException(roslib.exceptions.ROSLibException):
     """
     Exception type for errors in roslib.message routines
@@ -162,9 +171,9 @@
     @param current_time: currently not used. Only provided for API compatibility. current_time passes in the current time with respect to the message.
     @type  current_time: Time
     """
-    if type(val) in [int, long, float, bool]:
+    if type(val) in [int, int, float, bool]:
         return str(val)
-    elif isinstance(val, basestring):
+    elif isstring(val):
         #TODO: need to escape strings correctly
         if not val:
             return "''"
@@ -230,13 +239,13 @@
     if roslib.genpy.is_simple(field_type):
         # check sign and width
         if field_type in ['byte', 'int8', 'int16', 'int32', 'int64']:
-            if type(field_val) not in [long, int]:
+            if type(field_val) not in [int, int]:
                 raise SerializationError('field %s must be an integer type'%field_name)
             maxval = int(math.pow(2, _widths[field_type]-1))
             if field_val >= maxval or field_val <= -maxval:
                 raise SerializationError('field %s exceeds specified width [%s]'%(field_name, field_type))
         elif field_type in ['char', 'uint8', 'uint16', 'uint32', 'uint64']:
-            if type(field_val) not in [long, int] or field_val < 0:
+            if type(field_val) not in [int, int] or field_val < 0:
                 raise SerializationError('field %s must be unsigned integer type'%field_name)
             maxval = int(math.pow(2, _widths[field_type]))
             if field_val >= maxval:
@@ -245,7 +254,7 @@
             if field_val not in [True, False, 0, 1]:
                 raise SerializationError('field %s is not a bool'%(field_name))
     elif field_type == 'string':
-        if type(field_val) == unicode:
+        if type(field_val) == str:
             raise SerializationError('field %s is a unicode string instead of an ascii string'%field_name)
         elif type(field_val) != str:
             raise SerializationError('field %s must be of type str'%field_name)
@@ -299,12 +308,12 @@
             raise TypeError("Message constructor may only use args OR keywords, not both")
         if args:
             if len(args) != len(self.__slots__):
-                raise TypeError, "Invalid number of arguments, args should be %s"%str(self.__slots__)+" args are"+str(args)
+                raise TypeError("Invalid number of arguments, args should be %s"%str(self.__slots__)+" args are"+str(args))
             for i, k in enumerate(self.__slots__):
                 setattr(self, k, args[i])
         else:
             # validate kwds
-            for k,v in kwds.iteritems():
+            for k,v in kwds.items():
                 if not k in self.__slots__:
                     raise AttributeError("%s is not an attribute of %s"%(k, self.__class__.__name__))
             # iterate through slots so all fields are initialized.
@@ -326,7 +335,7 @@
         """
         support for Python pickling
         """
-        for x, val in itertools.izip(self.__slots__, state):
+        for x, val in zip(self.__slots__, state):
             setattr(self, x, val)


     def _get_types(self):
@@ -403,9 +412,13 @@
     @return: printable representation of  msg args
     @rtype: str
     """
-    import cStringIO
+    try:
+        from cStringIO import StringIO # Python 2.x
+    except ImportError:
+        from io import StringIO # Python 3.x
+
     if buff is None:
-        buff = cStringIO.StringIO()
+        buff = StringIO()
     for f in msg.__slots__:
         if isinstance(getattr(msg, f), Message):
             get_printable_message_args(getattr(msg, f), buff=buff, prefix=(prefix+f+'.'))
@@ -432,7 +445,7 @@
                 setattr(msg, f, keys[v])
             else:
                 raise ROSMessageException("No key named [%s]"%(v))
-        elif isinstance(def_val, roslib.rostime.TVal) and type(v) in (int, long):
+        elif isinstance(def_val, roslib.rostime.TVal) and type(v) in (int, int):
             #special case to handle time value represented as a single number
             #TODO: this is a lossy conversion
             if isinstance(def_val, roslib.rostime.Time):
@@ -492,7 +505,7 @@
         #print "DICT ARGS", msg_args
         #print "ACTIVE SLOTS",msg.__slots__


-        for f, v in msg_args.iteritems():
+        for f, v in msg_args.items():
             # assume that an empty key is actually an empty string
             if v == None:
                 v = ''
@@ -507,7 +520,7 @@
         elif len(msg_args) < len(msg.__slots__):
             raise ROSMessageException("Not enough arguments:\n * Given: %s\n * Expected: %s"%(msg_args, msg.__slots__))


-        for f, v in itertools.izip(msg.__slots__, msg_args):
+        for f, v in zip(msg.__slots__, msg_args):
             _fill_val(msg, f, v, keys, prefix)
     else:
         raise ValueError("invalid msg_args type: %s"%str(msg_args))