From 67fe08b106d6a312a1abfd86aafa6b0a6ba5fd86 Mon Sep 17 00:00:00 2001
From: scott snyder <sss@karma>
Date: Thu, 18 Apr 2019 16:35:20 +0200
Subject: [PATCH] PyUtils: Initial py3 porting.

Not yet intended to be complete --- only what's needed by basic Athena
and configuration jobs.
---
 Tools/PyUtils/python/Decorators.py | 21 +++++++-------
 Tools/PyUtils/python/Helpers.py    | 22 ++++++++++----
 Tools/PyUtils/python/RootUtils.py  | 46 ++++++++++++++++--------------
 3 files changed, 50 insertions(+), 39 deletions(-)

diff --git a/Tools/PyUtils/python/Decorators.py b/Tools/PyUtils/python/Decorators.py
index 5865453eb67..5e1eb054882 100644
--- a/Tools/PyUtils/python/Decorators.py
+++ b/Tools/PyUtils/python/Decorators.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 
 # @author: Sebastien Binet <binet@cern.ch>
 # @date:   March 2008
@@ -6,7 +6,7 @@
 #           from here:
 #           http://www.phyast.pitt.edu/~micheles/python/documentation.html
 #
-from __future__ import with_statement
+from __future__ import with_statement, print_function
 
 __version__ = "$Revision$"
 __author__  = "Sebastien Binet <binet@cern.ch>"
@@ -14,7 +14,7 @@ __author__  = "Sebastien Binet <binet@cern.ch>"
 __all__ = [
     'memoize',
     'forking',
-    'async',
+    'async_decor',
     ]
 
 import sys
@@ -45,7 +45,6 @@ def memoize(func, *args):
 
 # FIXME: does not work... func is an instance of FunctionMaker which cannot
 #        be pickled...
-import __builtin__
 @decorator
 def mp_forking(func, *args, **kwargs):
     import multiprocessing as mp
@@ -59,7 +58,7 @@ def mp_forking(func, *args, **kwargs):
             try:
                 res = func(*args, **kwargs)
             # catch *everything* and 're-raise'
-            except BaseException,err:
+            except BaseException as err:
                 #import traceback; traceback.print_exc()
                 res = err
             q.put(res)
@@ -82,7 +81,7 @@ def reraise_exception(new_exc, exc_info=None):
     if exc_info is None:
         exc_info = sys.exc_info()
     _exc_class, _exc, tb = exc_info
-    raise new_exc.__class__, new_exc, tb
+    raise new_exc.__class__ (new_exc, tb)
     
 @decorator
 def forking(func, *args, **kwargs):
@@ -122,17 +121,17 @@ def forking(func, *args, **kwargs):
         try:
             result = func(*args, **kwargs)
             status = 0
-        except (Exception, KeyboardInterrupt), exc:
+        except (Exception, KeyboardInterrupt) as exc:
             import traceback
             exc_string = traceback.format_exc(limit=10)
             for l in exc_string.splitlines():
-                print "[%d]"%os.getpid(),l.rstrip()
+                print ("[%d]"%os.getpid(),l.rstrip())
             result = exc, exc_string
             status = 1
         with os.fdopen(pwrite, 'wb') as f:
             try:
                 pickle.dump((status,result), f, pickle.HIGHEST_PROTOCOL)
-            except pickle.PicklingError, exc:
+            except pickle.PicklingError as exc:
                 pickle.dump((2,exc), f, pickle.HIGHEST_PROTOCOL)
         os._exit(0)
     pass # forking
@@ -147,7 +146,7 @@ def _async_on_success(result): # default implementation
 def _async_on_failure(exc_info): # default implementation
     "Called if the function fails"
     _exc_class, _exc, tb = exc_info
-    raise _exc_class, _exc, tb
+    raise _exc_class (_exc, tb)
     pass
 
 def _async_on_closing(): # default implementation
@@ -193,7 +192,7 @@ class Async(object):
         return thread
 
 # default async decorator: using processes
-def async(async_type='mp'):
+def async_decor(async_type='mp'):
     if async_type in ("mp", "multiprocessing"):
         from multiprocessing import Process
         factory = Process
diff --git a/Tools/PyUtils/python/Helpers.py b/Tools/PyUtils/python/Helpers.py
index 19cd0cd27eb..81b95cb345b 100644
--- a/Tools/PyUtils/python/Helpers.py
+++ b/Tools/PyUtils/python/Helpers.py
@@ -1,27 +1,32 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 
 # @author: Sebastien Binet <binet@cern.ch>
 # @date:   March 2007
 #
 #
-from __future__ import with_statement
+from __future__ import with_statement, print_function
 
 __version__ = "$Revision$"
 __author__  = "Sebastien Binet <binet@cern.ch>"
 
 import sys
 import os
+import six
 
 from AthenaCommon.Logging import log
 
 
 def ROOT6Setup():
    log.info('executing ROOT6Setup')
-   import __builtin__
-   oldimporthook = __builtin__.__import__
+   if six.PY3:
+      import builtins as builtin_mod
+   else:
+      import __builtin__ as builtin_mod
+   oldimporthook = builtin_mod.__import__
    autoload_var_name = 'ROOT6_NamespaceAutoloadHook'
    
    def root6_importhook(name, globals={}, locals={}, fromlist=[], level=-1):
+       if six.PY3 and level < 0: level = 0
        m = oldimporthook(name, globals, locals, fromlist, level)
        if m and (m.__name__== 'ROOT' or name[0:4]=='ROOT'):
           log.debug('Python import module=%s  fromlist=%s'%(name, str(fromlist)))
@@ -40,7 +45,7 @@ def ROOT6Setup():
                 pass
        return m
    
-   __builtin__.__import__ = root6_importhook
+   builtin_mod.__import__ = root6_importhook
       
 
 
@@ -83,6 +88,11 @@ class ShutUp(object):
             os.dup2( sys.stderr.fileno(), self.save_err.fileno() )
             os.dup2( sys.stdout.fileno(), self.save_out.fileno() )
         return
+
+    def __del__ (self):
+       self.save_err.close()
+       self.save_out.close()
+       return
     
     def mute(self):
         if not self._dummy:
@@ -108,7 +118,7 @@ class ShutUp(object):
                 if re.match(filter, l):
                     printOut = False
             if printOut:
-                print "PyRoot:",l.replace("\n","")
+                print ("PyRoot:",l.replace("\n",""))
             pass
         return
 
diff --git a/Tools/PyUtils/python/RootUtils.py b/Tools/PyUtils/python/RootUtils.py
index 322488b2736..7151fef588e 100644
--- a/Tools/PyUtils/python/RootUtils.py
+++ b/Tools/PyUtils/python/RootUtils.py
@@ -1,11 +1,11 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 
 # @file PyUtils.RootUtils
 # @author Sebastien Binet
 # @purpose a few utils to ease the day-to-day work with ROOT
 # @date November 2009
 
-from __future__ import with_statement
+from __future__ import with_statement, print_function
 
 __doc__ = "a few utils to ease the day-to-day work with ROOT"
 __version__ = "$Revision: 739816 $"
@@ -81,7 +81,7 @@ def root_compile(src=None, fname=None, batch=True):
         import tempfile
         src_file = tempfile.NamedTemporaryFile(prefix='root_aclic_',
                                                suffix='.cxx')
-        src_file.write(textwrap.dedent(src))
+        src_file.write(textwrap.dedent(src).encode())
         src_file.flush()
         src_file.seek(0)
         fname = src_file.name
@@ -146,15 +146,15 @@ def _pythonize_tfile():
         FIXME: probably doesn't follow python file-like conventions...
         """
         SZ = 4096
-        
+
         if size>=0:
             #size = _adjust_sz(size)
-            #print "-->0",self.tell(),size
+            #print ("-->0",self.tell(),size)
             c_buf = read_root_file(self, size)
             if c_buf and c_buf.sz:
-                #print "-->1",self.tell(),c_buf.sz
+                #print ("-->1",self.tell(),c_buf.sz)
                 #self.seek(c_buf.sz+self.tell())
-                #print "-->2",self.tell()
+                #print ("-->2",self.tell())
                 buf = c_buf.buffer()
                 _set_byte_size (buf, c_buf.sz)
                 return str(buf[:])
@@ -272,32 +272,32 @@ class RootFileDumper(object):
                     _n = int(itr_entries)
                     itr_entries = xrange(_n)
                 except ValueError:
-                    print "** err ** invalid 'itr_entries' argument. will iterate over all entries."
+                    print ("** err ** invalid 'itr_entries' argument. will iterate over all entries.")
                     itr_entries = xrange(nentries)
         else:
             itr_entries = xrange(itr_entries)
                 
         for ientry in itr_entries:
             hdr = ":: entry [%05i]..." % (ientry,)
-            #print hdr
-            #print >> self.fout, hdr
+            #print (hdr)
+            #print (hdr, file=self.fout)
             err = tree.LoadTree(ientry)
             if err < 0:
-                print "**err** loading tree for entry",ientry
+                print ("**err** loading tree for entry",ientry)
                 self.allgood = False
                 break
 
             nbytes = tree.GetEntry(ientry)
             if nbytes <= 0:
-                print "**err** reading entry [%s] of tree [%s]" % (ientry, tree_name)
+                print ("**err** reading entry [%s] of tree [%s]" % (ientry, tree_name))
                 hdr = ":: entry [%05i]... [ERR]" % (ientry,)
-                print hdr
+                print (hdr)
                 self.allgood = False
                 continue
 
             for br_name in leaves:
                 hdr = "::  branch [%s]..." % (br_name,)
-                #print hdr
+                #print (hdr)
                 #tree.GetBranch(br_name).GetEntry(ientry)
                 py_name = [br_name]
 
@@ -313,15 +313,15 @@ class RootFileDumper(object):
                     else:
                         val = tuple(vals)
                 if not (val is None):
-                    #print "-->",val,br_name
+                    #print ("-->",val,br_name)
                     try:
                         vals = _pythonize(val, py_name, True)
-                    except Exception, err:
-                        print "**err** for branch [%s] val=%s (type=%s)" % (
+                    except Exception as err:
+                        print ("**err** for branch [%s] val=%s (type=%s)" % (
                             br_name, val, type(val),
-                            )
+                            ))
                         self.allgood = False
-                        print err
+                        print (err)
                     for o in vals:
                         n = map(str, o[0])
                         v = o[1]
@@ -336,9 +336,11 @@ def _test_main():
     root = import_root()
     def no_raise(msg, fct, *args, **kwds):
         caught = False
+        err = None
         try:
             fct(*args, **kwds)
-        except Exception, err:
+        except Exception as xerr:
+            err = xerr
             caught = True
         assert not caught, "%s:\n%s\nERROR" % (msg, err,)
 
@@ -351,12 +353,12 @@ def _test_main():
     # PvG workaround for ROOT-7059
     dummy = tempfile.NamedTemporaryFile(prefix="foo_",suffix=".cxx")
     with tempfile.NamedTemporaryFile(prefix="foo_",suffix=".cxx") as tmp:
-        print >> tmp, "void foo2() { return ; }"
+        tmp.write (b"void foo2() { return ; }\n")
         tmp.flush()
         no_raise("problem compiling a file",
                  fct=root_compile, fname=tmp.name)
 
-    print "OK"
+    print ("OK")
     return True
 
 if __name__ == "__main__":
-- 
GitLab