Skip to content

Commit

Permalink
uHAL : Update Python bindings to support Python 3; refs #127
Browse files Browse the repository at this point in the history
  • Loading branch information
tswilliams committed Jan 4, 2019
1 parent 01f3e93 commit fb3dc5b
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 38 deletions.
7 changes: 6 additions & 1 deletion uhal/pycohal/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ PackagerEmail = tom.williams@cern.ch
PythonModules = ["uhal"]
LibraryFile = pkg/uhal/_core.so

ifeq ($(shell python -c "import sys; print(sys.version_info[0])"),3)
EXTERN_BOOST_PYTHON_LIB = boost_python3
else
EXTERN_BOOST_PYTHON_LIB = boost_python
endif

IncludePaths = include \
${EXTERN_BOOST_INCLUDE_PREFIX} \
Expand Down Expand Up @@ -49,7 +54,7 @@ Libraries = \
pugixml \
\
boost_filesystem \
boost_python \
${EXTERN_BOOST_PYTHON_LIB} \
boost_regex \
boost_system \
boost_thread \
Expand Down
28 changes: 16 additions & 12 deletions uhal/pycohal/pkg/uhal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
import sys

try:
from _core import *
from ._core import *
except ImportError as e:
from os import environ
if ('LD_LIBRARY_PATH' not in environ) or '/opt/cactus/lib' not in environ['LD_LIBRARY_PATH'].split():
new_msg = (e.message +
"\nN.B. ImportError raised when uHAL's __init__.py tries to load python bindings library" +
'\n Maybe you need to add "/opt/cactus/lib", or some other path, to the "LD_LIBRARY_PATH" environment variable?')
raise type(e), type(e)(new_msg), sys.exc_info()[2]
msg_suffix = '\nN.B. ImportError (or derived exception) raised when uHAL\'s __init__.py tries to load python bindings library\n Maybe you need to add "/opt/cactus/lib", or some other path, to the "LD_LIBRARY_PATH" environment variable?'
if sys.version_info[0] > 2:
# raise type(e)(type(e)(new_msg)).with_traceback()
exec('raise type(e)(e.msg + msg_suffix) from e')
else:
exec('raise type(e), type(e)(e.message + msg_suffix), sys.exc_info()[2]')
else:
raise

Expand All @@ -26,10 +28,12 @@ def _exception_to_string(self):
##################################################
# Pythonic additions to the ValWord_uint32 API

def _ValWord_to_long(self):
return long(int(self))
if sys.version_info[0] <= 2:
def _ValWord_to_long(self):
return long(int(self))
ValWord_uint32.__long__ = _ValWord_to_long

ValWord_uint32.__long__ = _ValWord_to_long
ValWord_uint32.__index__ = ValWord_uint32.__int__


def _add_int_method_to_ValWord(method_name, unary=False):
Expand All @@ -40,7 +44,7 @@ def valWord_method(self):
else:
def valWord_method(self, other):
int_type = int
if isinstance(int(self), long) or ( not isinstance(other, str) and isinstance(int(other), long) ):
if (sys.version_info[0] <= 2) and (isinstance(int(self), long) or ( not isinstance(other, str) and isinstance(int(other), long) )):
int_type = long
int_method = getattr(int_type, method_name)
if isinstance(other, int_type) or isinstance(other, str):
Expand Down Expand Up @@ -77,8 +81,8 @@ def _add_int_methods_to_ValWord(method_names, unary=False):
_add_int_method_to_ValWord('__format__')

# Unary comparison operator (used in "if valWord")
_add_int_method_to_ValWord('__nonzero__', unary=True)
_add_int_method_to_ValWord('__bool__' if (sys.version_info[0] > 2) else '__nonzero__', unary=True)

# Binary comparison operator
_add_int_method_to_ValWord('__cmp__')
# Binary comparison operators
_add_int_methods_to_ValWord(['__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__'] if (sys.version_info[0] > 2) else ['__cmp__'])

4 changes: 4 additions & 0 deletions uhal/pycohal/src/common/cactus_pycohal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,11 @@ BOOST_PYTHON_MODULE ( _core )
.def ( "mask", static_cast< const uint32_t& ( uhal::ValWord<uint32_t>::* ) () const > ( &uhal::ValWord<uint32_t>::mask ) , pycohal::const_ref_return_policy() )
.def ( "__str__", static_cast< std::string (*) ( const uhal::ValWord<uint32_t>& ) > ( &pycohal::convert_to_string ) )
.def ( "__int__", static_cast< uint32_t ( uhal::ValWord<uint32_t>::* ) () const> ( &uhal::ValWord<uint32_t>::value ) )
#if PY_VERSION_HEX >= 0x03000000
.def ( "__index__", static_cast< uint32_t ( uhal::ValWord<uint32_t>::* ) () const> ( &uhal::ValWord<uint32_t>::value ) )
#else
.def ( "__hex__", pycohal::hex_string )
#endif
;
// Wrap uhal::ValVector<uint32_t>
class_<uhal::ValVector<uint32_t> > ( "ValVector_uint32", init< const uhal::ValVector<uint32_t>& >() )
Expand Down
54 changes: 36 additions & 18 deletions uhal/tests/scripts/test_pycohal
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,13 @@ class TestValWordIntMethods(unittest.TestCase):
if valid:
x0 = 0
reg0 = uhal.tests.get_dummy_ValWord(x0, True)
self.assertEqual ( x0.__nonzero__() , reg0.__nonzero__() )
if (sys.version_info[0] > 2):
self.assertEqual ( x0.__bool__() , reg0.__bool__() )
self.assertEqual ( x1.__bool__() , reg1.__bool__() )
else:
self.assertEqual ( x0.__nonzero__() , reg0.__nonzero__() )
self.assertEqual ( x1.__nonzero__() , reg1.__nonzero__() )
self.assertEqual ( bool(x0) , bool(reg0) )
self.assertEqual ( x1.__nonzero__() , reg1.__nonzero__() )
self.assertEqual ( bool(x1) , bool(reg1) )
else:
self.assertRaises( uhal.NonValidatedMemory, bool , (reg1) )
Expand All @@ -314,8 +318,22 @@ class TestValWordIntMethods(unittest.TestCase):
reg1b = uhal.tests.get_dummy_ValWord(x1, True)
self.assertAllEqual ( x1 == x1 , reg1 == x1 , x1 == reg1 , reg1 == reg1b )
else:
self.assertRaises( uhal.NonValidatedMemory, reg1.__cmp__, (x1) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__cmp__, (reg2) )
if (sys.version_info[0] > 2):
self.assertRaises( uhal.NonValidatedMemory, reg1.__lt__, (x1) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__le__, (x1) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__eq__, (x1) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__ne__, (x1) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__gt__, (x1) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__ge__, (x1) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__lt__, (reg2) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__le__, (reg2) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__eq__, (reg2) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__ne__, (reg2) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__gt__, (reg2) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__ge__, (reg2) )
else:
self.assertRaises( uhal.NonValidatedMemory, reg1.__cmp__, (x1) )
self.assertRaises( uhal.NonValidatedMemory, reg1.__cmp__, (reg2) )

# __format__
if sys.hexversion >= 0x020600F0:
Expand Down Expand Up @@ -436,7 +454,7 @@ class TestBlock(unittest.TestCase):


def test_block_write_read(self):
for N in [1, 1024/4, 1024, 1024*1024/4]:
for N in [1, 1024//4, 1024, 1024*1024//4]:
self.exe_test_block_write_read(N)

def exe_test_block_offset_write_read(self, N, offset):
Expand Down Expand Up @@ -470,7 +488,7 @@ class TestBlock(unittest.TestCase):
self.assertEqual( xx, [x for x in memVals] )

def test_block_offset_write_read(self):
for N in [1, 1024/4, 1024, 1024*1024/4]:
for N in [1, 1024//4, 1024, 1024*1024//4]:
for offset in [0, min(N,self.hw.getNode("MEM").getSize()-N), randint(0,self.hw.getNode("MEM").getSize()-N)]:
self.exe_test_block_offset_write_read(N, offset)

Expand Down Expand Up @@ -523,7 +541,7 @@ class TestRawClient(unittest.TestCase):
self.assertEqual( int(reg) , x )

def test_mem_write_read_rawclient(self):
N = 1024*1024/4
N = 1024*1024//4
client = self.hw.getClient()
# Queue IPBus transactions
xx = list_randuint32s(N)
Expand Down Expand Up @@ -563,7 +581,7 @@ class TestRawClient(unittest.TestCase):
total = 0
xx = []
for i in range(N):
xx.append( randint(0,0xffffffff/1024) )
xx.append( randint(0,0xffffffff//1024) )
total += xx[i]
addr = self.hw.getNode( "SUBSYSTEM1.REG" ).getAddress()
client.write( addr, xx[0] )
Expand Down Expand Up @@ -807,7 +825,7 @@ class TestPrintValMem( unittest.TestCase ):

def test_ValVector(self):
self.exe_ValVector_test( [0, 42, 56, 75] )
self.exe_ValVector_test( list_randuint32s(1024*1024/4) )
self.exe_ValVector_test( list_randuint32s(1024*1024//4) )


# Run the tests
Expand All @@ -816,14 +834,14 @@ if __name__ == '__main__':
# Grabbing connections xml file from args, and leaving rest of args for unittest
if len(sys.argv)<3:
sys.stderr.write("ERROR: Connections file not specified\n")
print __doc__
print(__doc__)
sys.exit(2)

try:
opts, args = getopt.getopt([sys.argv.pop(1),sys.argv.pop(1)], "c:", ["connections-file="])
except getopt.GetoptError, err:
print err
print __doc__
except getopt.GetoptError as err:
print(err)
print(__doc__)
sys.exit(2)

CONNECTIONS_FILE = opts[0][1]
Expand All @@ -832,14 +850,14 @@ if __name__ == '__main__':

# Check that '-v' is first remaining option if present - otherwise unittest module fails, with incomprehensible stack trace
if ( sys.argv.count('-v')==1 and sys.argv[1]!='-v' ) or sys.argv.count('-v')>1 :
print "Invalid usage of '-v' option - if used it should only come directly after connection file"
print "E.g: To run only the unit tests under TestPrintValMem try ..."
print " python test_pycohal -c file::///dir/to/connections_file.xml -v TestPrintValMem"
print __doc__
print("Invalid usage of '-v' option - if used it should only come directly after connection file")
print("E.g: To run only the unit tests under TestPrintValMem try ...")
print(" python test_pycohal -c file::///dir/to/connections_file.xml -v TestPrintValMem")
print(__doc__)
sys.exit(2)

# Now run tests ...
print 'Running tests using connections file "'+CONNECTIONS_FILE+'"\n'
print('Running tests using connections file "'+CONNECTIONS_FILE+'"\n')
uhal.setLogLevelTo( uhal.LogLevel.FATAL )
unittest.main()

16 changes: 9 additions & 7 deletions uhal/tests/scripts/uhal_test_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,14 @@ def get_dummyhardware_status( cmd ):
else:
return StdOut+" DummyHardwares running"


def convert_to_utf(byte_string):
if sys.version_info[0] > 2:
return str(byte_string, 'utf-8')
else:
return byte_string


def background_run_command(cmd , proc_list):
"""
Run command in separate thread, ignoring stdout and stderr
Expand All @@ -227,7 +235,7 @@ def runInThread(cmd , proc_list):
elif exit_code:
msg = "+ *** ERROR OCCURED (exit code = %s, time elapsed = %s seconds) IN BACKGROUND COMMAND '%s' ***\n" % (exit_code, cmd_duration, cmd)
msg += " ----- START OF STDOUT -----\n"
msg += p.stdout.read()
msg += convert_to_utf(p.stdout.read())
msg += "\n ----- END OF STDOUT -----"
print(msg)
else:
Expand All @@ -238,7 +246,6 @@ def runInThread(cmd , proc_list):
thread.start()



def run_command(cmd, verbose=True):
"""
Run command, printing stdout and stderr to stdout if argument verbose = True
Expand All @@ -259,11 +266,6 @@ def run_command(cmd, verbose=True):
stdout = []
last = time.time()

def convert_to_utf(byte_string):
if sys.version_info[0] > 2:
return str(byte_string, 'utf-8')
else:
return byte_string

while True:
current = time.time()
Expand Down

0 comments on commit fb3dc5b

Please sign in to comment.