Hi Thien,
ACK from me.
Best Regards,
ThuanTr
-----Original Message-----
From: Thien Minh Huynh <thien.m.hu...@dektech.com.au>
Sent: Thursday, August 13, 2020 10:26 AM
To: Thuan Tran <thuan.t...@dektech.com.au>; Minh Hon Chau <minh.c...@dektech.com.au>;
Thang Duc Nguyen <thang.d.ngu...@dektech.com.au>
Cc: opensaf-devel@lists.sourceforge.net; Thien Minh Huynh
<thien.m.hu...@dektech.com.au>
Subject: [PATCH 1/1] pyosaf: Support python3 [#3210]
Adapt pyosaf to support python3, and be compatible with python2
---
python/pyosaf/saAis.py | 51 +++++++++++++++++++++++----
python/pyosaf/saAmf.py | 8 +++--
python/pyosaf/saImm.py | 4 ++-
python/pyosaf/saLog.py | 4 ++-
python/pyosaf/utils/immoi/agent.py | 2 +-
python/pyosaf/utils/immom/accessor.py | 10 +++---
python/pyosaf/utils/immom/agent.py | 11 +++---
python/pyosaf/utils/immom/ccb.py | 19 +++++-----
python/pyosaf/utils/immom/iterator.py | 9 ++---
python/pyosaf/utils/immom/object.py | 2 +-
python/pyosaf/utils/ntf/producer.py | 24 +++++++------
src/imm/tools/immxml-merge | 32 ++++++++++++-----
12 files changed, 123 insertions(+), 53 deletions(-)
diff --git a/python/pyosaf/saAis.py b/python/pyosaf/saAis.py
index 178ea554c..912523e69 100644
--- a/python/pyosaf/saAis.py
+++ b/python/pyosaf/saAis.py
@@ -18,13 +18,15 @@
'''
Common types and prototypes used by all modules in pyosaf
'''
+import sys
from os import environ
-
import ctypes
from ctypes import pointer, POINTER, cast, byref, c_void_p, Structure, \
Union, CDLL
from pyosaf.saEnumConst import Enumeration, Const
+PY3 = True if sys.version_info[0] == 3 else False
+
SaInt8T = ctypes.c_char
SaInt16T = ctypes.c_short
SaInt32T = ctypes.c_int
@@ -39,7 +41,21 @@ SaVoidPtr = c_void_p
# Types used by the NTF/IMMS service
SaFloatT = ctypes.c_float
SaDoubleT = ctypes.c_double
-SaStringT = ctypes.c_char_p
+if PY3:
+ class SaStringT(ctypes.c_char_p):
+ def __init__(self, value=''):
+ if value is not None:
+ value = value.encode('utf-8')
+ super(SaStringT, self).__init__(value)
+
+ def __str__(self):
+ if self.value is not None:
+ return self.value.decode('utf-8')
+ else:
+ return self.__repr__()
+else:
+ SaStringT = ctypes.c_char_p
+
SaTimeT = SaInt64T
SaInvocationT = SaUint64T
@@ -177,6 +193,12 @@ if environ.get('SA_ENABLE_EXTENDED_NAMES') == '1':
immdll.saAisNameLend.argtypes = [SaConstStringT,
POINTER(SaNameT)]
immdll.saAisNameLend.restype = None
+ if PY3:
+ # Add name_in_bytes attribute to this object as
a workaround
+ # To keep the `name` in bytes not to be freed
by garbarge
+ # collector when it's still refered in
`_opaque` of SaNameT
+ self.name_in_bytes = name.encode('utf-8')
+ name = self.name_in_bytes
immdll.saAisNameLend(name, BYREF(self))
@@ -185,7 +207,11 @@ if environ.get('SA_ENABLE_EXTENDED_NAMES') == '1':
"""
immdll.saAisNameBorrow.argtypes = [POINTER(SaNameT)]
immdll.saAisNameBorrow.restype = SaConstStringT
- return immdll.saAisNameBorrow(BYREF(self))
+ name = immdll.saAisNameBorrow(BYREF(self))
+ if PY3:
+ return name.decode('utf-8')
+
+ return name
else:
class SaNameT(Structure):
"""Contain names.
@@ -196,12 +222,17 @@ else:
def __init__(self, name=''):
"""Construct instance with contents of 'name'.
"""
+ if PY3:
+ name = name.encode('utf-8')
super(SaNameT, self).__init__(len(name), name)
def __str__(self):
"""Returns the content of SaNameT
"""
- return self.value
+ if PY3:
+ return self.value.decode('utf-8')
+ else:
+ return self.value
class SaVersionT(Structure):
@@ -211,6 +242,14 @@ class SaVersionT(Structure):
('majorVersion', SaUint8T),
('minorVersion', SaUint8T)]
+ def __init__(self, release='_', major=0, minor=0):
+ """Construct instance with contents of 'name'.
+ """
+ if PY3:
+ release = release[0].encode('utf-8')
+
+ super(SaVersionT, self).__init__(release, major, minor)
+
class SaLimitValueT(Union):
"""Contain the value of an implementation-specific limit.
@@ -259,7 +298,7 @@ def unmarshalNullArray(c_array):
if not c_array:
return []
ctype = c_array[0].__class__
- if ctype is str:
+ if ctype is str or (PY3 and ctype is SaStringT):
return unmarshalSaStringTArray(c_array)
val_list = []
for ptr in c_array:
@@ -278,7 +317,7 @@ def unmarshalSaStringTArray(c_array):
for ptr in c_array:
if not ptr:
break
- val_list.append(ptr)
+ val_list.append(str(ptr))
return val_list
diff --git a/python/pyosaf/saAmf.py b/python/pyosaf/saAmf.py
index 5d2fca628..ff9265d22 100644
--- a/python/pyosaf/saAmf.py
+++ b/python/pyosaf/saAmf.py
@@ -19,7 +19,7 @@ from ctypes import POINTER, Structure, CFUNCTYPE, CDLL, Union
from pyosaf.saAis import SaAisErrorT, SaInvocationT, SaNameT, SaUint64T, \
SaUint32T, SaTimeT, SaUint8T, SaInt64T, SaInt32T, SaDispatchFlagsT, \
SaVersionT, SaSelectionObjectT, SaEnumT, Enumeration, SaInt8T, \
- SaUint16T, Const, BYREF
+ SaUint16T, Const, BYREF, PY3
from pyosaf.saNtf import SaNtfIdentifierT, SaNtfCorrelationIdsT
# Only mirrors API calls implemented in osaf/libs/agents/saf/ava/ava_api.c
@@ -61,7 +61,11 @@ class SaAmfHealthcheckKeyT(Structure):
def __init__(self, key=''):
"""Construct instance with contents of 'key'.
"""
- super(SaAmfHealthcheckKeyT, self).__init__(key, len(key))
+ if PY3:
+ key = key.encode('utf-8')
+ super(SaAmfHealthcheckKeyT, self).__init__(key,
len(key))
+ else:
+ super(SaAmfHealthcheckKeyT, self).__init__(key,
len(key))
SaAmfHAStateT = SaEnumT
eSaAmfHAStateT = Enumeration((
diff --git a/python/pyosaf/saImm.py b/python/pyosaf/saImm.py
index e464dc17e..f167a4e4f 100644
--- a/python/pyosaf/saImm.py
+++ b/python/pyosaf/saImm.py
@@ -24,7 +24,7 @@ from ctypes import cast, pointer, POINTER, Structure, Union
from pyosaf.saAis import SaStringT, SaEnumT, SaInt32T, SaUint32T, SaInt64T, \
SaUint64T, SaTimeT, SaNameT, SaFloatT, SaDoubleT, SaStringT, SaAnyT
from pyosaf.saEnumConst import Enumeration, Const
-from pyosaf.saAis import SaVoidPtr
+from pyosaf.saAis import SaVoidPtr, PY3
saImm = Const()
@@ -72,6 +72,8 @@ def unmarshalSaImmValue(void_ptr, value_type):
if val_ptr and void_ptr:
if val_ptr == SaNameT:
return str(cast(void_ptr, POINTER(val_ptr))[0])
+ elif val_ptr == SaStringT and PY3:
+ return str(cast(void_ptr, POINTER(val_ptr))[0])
return cast(void_ptr, POINTER(val_ptr))[0]
return None
diff --git a/python/pyosaf/saLog.py b/python/pyosaf/saLog.py
index ad24b219b..039a47d4a 100644
--- a/python/pyosaf/saLog.py
+++ b/python/pyosaf/saLog.py
@@ -20,7 +20,7 @@ from ctypes import POINTER, CDLL, Structure, CFUNCTYPE,
create_string_buffer, \
from pyosaf.saAis import SaUint64T, Const, SaUint16T, SaVersionT, SaStringT, \
SaUint32T, SaBoolT, SaEnumT, Enumeration, SaInvocationT, SaAisErrorT,
\
BYREF, SaDispatchFlagsT, SaNameT, SaTimeT, SaSelectionObjectT, \
- SaUint8T, SaSizeT, SaInt8T, SaLimitValueT
+ SaUint8T, SaSizeT, SaInt8T, SaLimitValueT, PY3
from pyosaf import saNtf
# Only mirrors API calls implemented in osaf/libs/agents/saf/lga/lga_api.c
@@ -66,6 +66,8 @@ class SaLogBufferT(Structure):
_fields_ = [('logBufSize', SaSizeT),
('logBuf', POINTER(SaInt8T))]
def __init__(self, buf=''):
+ if PY3:
+ buf = buf.encode('utf-8')
super(SaLogBufferT, self).__init__(len(buf),
create_string_buffer(buf) if buf else None)
diff --git a/python/pyosaf/utils/immoi/agent.py b/python/pyosaf/utils/immoi/agent.py
index 74bd1330d..e0697b1ef 100644
--- a/python/pyosaf/utils/immoi/agent.py
+++ b/python/pyosaf/utils/immoi/agent.py
@@ -356,7 +356,7 @@ class OiAgent(object):
"""
_, class_desc = self.imm_om.get_class_description(class_name)
attr_desc = [attr for attr in class_desc if
- attr.attrName == attribute][0]
+ str(attr.attrName) == attribute][0]
return attr_desc.attrValueType
diff --git a/python/pyosaf/utils/immom/accessor.py b/python/pyosaf/utils/immom/accessor.py
index bed08d5fa..93ed84c85 100644
--- a/python/pyosaf/utils/immom/accessor.py
+++ b/python/pyosaf/utils/immom/accessor.py
@@ -121,11 +121,11 @@ class ImmOmAccessor(agent.OmAgentManager):
attr_list = unmarshalNullArray(attributes)
for attr in attr_list:
attr_range = list(range(attr.attrValuesNumber))
- attrs[attr.attrName] = [attr.attrValueType,
- [unmarshalSaImmValue(
- attr.attrValues[val],
- attr.attrValueType)
- for val in attr_range]]
+ attrs[str(attr.attrName)] = [
+ attr.attrValueType,
+ [unmarshalSaImmValue(attr.attrValues[val],
+ attr.attrValueType)
+ for val in attr_range]]
if 'SaImmAttrClassName' not in attrs and class_name:
attrs['SaImmAttrClassName'] = class_name
imm_obj = ImmObject(dn=object_name, attributes=attrs)
diff --git a/python/pyosaf/utils/immom/agent.py
b/python/pyosaf/utils/immom/agent.py
index dc91fc6ea..0413f1bd1 100644
--- a/python/pyosaf/utils/immom/agent.py
+++ b/python/pyosaf/utils/immom/agent.py
@@ -23,7 +23,7 @@ from ctypes import pointer
from pyosaf import saImmOm, saImm
from pyosaf.saAis import saAis, SaVersionT, SaNameT, SaAisErrorT, \
eSaAisErrorT, eSaBoolT, unmarshalNullArray
-from pyosaf.saImm import eSaImmScopeT
+from pyosaf.saImm import eSaImmScopeT, SaImmClassNameT, SaImmAttrNameT
from pyosaf.utils import decorate, initialize_decorate, log_err
# Decorate pure saImmOm* API's with error-handling retry and exception raising
@@ -211,7 +211,8 @@ class ImmOmAgent(OmAgentManager):
def attr_def_copy(attr_def):
""" Deep copy attributes """
attr_def_cpy = saImm.SaImmAttrDefinitionT_2()
- attr_def_cpy.attrName = attr_def.attrName[:]
+ attr_def_cpy.attrName = SaImmAttrNameT(
+ deepcopy(str(attr_def.attrName)))
attr_def_cpy.attrValueType = attr_def.attrValueType
attr_def_cpy.attrFlags = attr_def.attrFlags
@@ -220,7 +221,9 @@ class ImmOmAgent(OmAgentManager):
class_attrs = []
attr_defs = pointer(pointer(saImm.SaImmAttrDefinitionT_2()))
category = saImm.SaImmClassCategoryT()
- rc = saImmOmClassDescriptionGet_2(self.handle, class_name, category,
+ rc = saImmOmClassDescriptionGet_2(self.handle,
+ SaImmClassNameT(class_name),
+ category,
attr_defs)
if rc != eSaAisErrorT.SA_AIS_OK:
log_err("saImmOmClassDescriptionGet_2 FAILED - %s" %
@@ -253,7 +256,7 @@ class ImmOmAgent(OmAgentManager):
else:
for attr_desc in class_attrs:
if attr_desc.attrFlags & saImm.saImm.SA_IMM_ATTR_RDN:
- return attr_desc.attrName
+ return str(attr_desc.attrName)
def invoke_admin_operation(self, dn, op_id, params=None):
""" Invoke admin op for dn
diff --git a/python/pyosaf/utils/immom/ccb.py b/python/pyosaf/utils/immom/ccb.py
index 8edd526b1..a23f777d3 100644
--- a/python/pyosaf/utils/immom/ccb.py
+++ b/python/pyosaf/utils/immom/ccb.py
@@ -22,7 +22,8 @@ from ctypes import c_void_p, pointer, cast, POINTER
from pyosaf.saAis import eSaAisErrorT, SaNameT, SaStringT, SaFloatT, \
unmarshalNullArray, SaDoubleT, SaTimeT, SaUint64T, SaInt64T, SaUint32T, \
SaInt32T
-from pyosaf.saImm import eSaImmScopeT, eSaImmValueTypeT, SaImmAttrValuesT_2
+from pyosaf.saImm import eSaImmScopeT, eSaImmValueTypeT, SaImmAttrValuesT_2, \
+ SaImmAttrNameT, SaImmClassNameT
from pyosaf import saImm
from pyosaf import saImmOm
from pyosaf.utils.immom import agent
@@ -44,13 +45,13 @@ def _value_to_ctype_ptr(value_type, value):
if value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAINT32T:
ctypeptr = cast(pointer(SaInt32T(value)), c_void_p)
elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAUINT32T:
- ctypeptr = cast(pointer(SaUint32T(long(value))), c_void_p)
+ ctypeptr = cast(pointer(SaUint32T(value)), c_void_p)
elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAINT64T:
- ctypeptr = cast(pointer(SaInt64T(long(value))), c_void_p)
+ ctypeptr = cast(pointer(SaInt64T(value)), c_void_p)
elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAUINT64T:
- ctypeptr = cast(pointer(SaUint64T(long(value))), c_void_p)
+ ctypeptr = cast(pointer(SaUint64T(value)), c_void_p)
elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SATIMET:
- ctypeptr = cast(pointer(SaTimeT(long(value))), c_void_p)
+ ctypeptr = cast(pointer(SaTimeT(value)), c_void_p)
elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SANAMET:
ctypeptr = cast(pointer(SaNameT(value)), c_void_p)
elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAFLOATT:
@@ -172,7 +173,7 @@ class Ccb(ImmOmAgent):
for attr_name, type_values in obj.attrs.items():
values = type_values[1]
attr = SaImmAttrValuesT_2()
- attr.attrName = attr_name
+ attr.attrName = SaImmAttrNameT(attr_name)
attr.attrValueType = type_values[0]
attr.attrValuesNumber = len(values)
@@ -180,7 +181,7 @@ class Ccb(ImmOmAgent):
attr_values.append(attr)
rc = agent.saImmOmCcbObjectCreate_2(self.ccb_handle,
- obj.class_name,
+
SaImmClassNameT(obj.class_name),
parent_name,
attr_values)
if rc != eSaAisErrorT.SA_AIS_OK:
@@ -255,7 +256,7 @@ class Ccb(ImmOmAgent):
_, attr_def_list = self.get_class_description(class_name)
value_type = None
for attr_def in attr_def_list:
- if attr_def.attrName == attr_name:
+ if str(attr_def.attrName) == attr_name:
value_type = attr_def.attrValueType
break
if value_type:
@@ -271,7 +272,7 @@ class Ccb(ImmOmAgent):
attr_mod = saImmOm.SaImmAttrModificationT_2()
attr_mod.modType = mod_type
attr_mod.modAttr = SaImmAttrValuesT_2()
- attr_mod.modAttr.attrName = attr_name
+ attr_mod.modAttr.attrName = SaImmAttrNameT(attr_name)
attr_mod.modAttr.attrValueType = value_type
attr_mod.modAttr.attrValuesNumber = len(values)
attr_mod.modAttr.attrValues = marshal_c_array(value_type,
diff --git a/python/pyosaf/utils/immom/iterator.py
b/python/pyosaf/utils/immom/iterator.py
index 7402c9427..91c5751c0 100644
--- a/python/pyosaf/utils/immom/iterator.py
+++ b/python/pyosaf/utils/immom/iterator.py
@@ -105,10 +105,11 @@ class SearchIterator(agent.OmAgentManager, Iterator):
attr_list = unmarshalNullArray(attributes)
for attr in attr_list:
attr_range = list(range(attr.attrValuesNumber))
- attrs[attr.attrName] = [attr.attrValueType,
- [unmarshalSaImmValue(attr.attrValues[val],
- attr.attrValueType)
- for val in attr_range]]
+ attrs[str(attr.attrName)] = [
+ attr.attrValueType,
+ [unmarshalSaImmValue(attr.attrValues[val],
+ attr.attrValueType)
+ for val in attr_range]]
return ImmObject(str(obj_name), attrs)
@bad_handle_retry
diff --git a/python/pyosaf/utils/immom/object.py
b/python/pyosaf/utils/immom/object.py
index 0cef920cc..6e80abfae 100644
--- a/python/pyosaf/utils/immom/object.py
+++ b/python/pyosaf/utils/immom/object.py
@@ -82,7 +82,7 @@ class ImmObject(object):
SaImmAttrNameT: Attribute value type
"""
for attr_def in self.class_desc[self.class_name]:
- if attr_def.attrName == attr_name:
+ if str(attr_def.attrName) == attr_name:
return attr_def.attrValueType
def __attr_is_multi_value(self, attr_name):
diff --git a/python/pyosaf/utils/ntf/producer.py
b/python/pyosaf/utils/ntf/producer.py
index 1d5422536..b9a0ebf9e 100644
--- a/python/pyosaf/utils/ntf/producer.py
+++ b/python/pyosaf/utils/ntf/producer.py
@@ -19,7 +19,8 @@
import ctypes
from pyosaf import saNtf
-from pyosaf.saAis import eSaBoolT, eSaAisErrorT, SaVoidPtr
+from pyosaf.saNtf import eSaNtfValueTypeT
+from pyosaf.saAis import eSaBoolT, eSaAisErrorT, SaVoidPtr, SaNameT, PY3
from pyosaf.utils import log_warn, log_err, bad_handle_retry
from pyosaf.utils.ntf import agent as ntf
@@ -87,6 +88,8 @@ class NtfProducer(ntf.NtfAgent):
elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_LDAP_NAME \
or value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_STRING \
or value_type ==
saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_IPADDRESS:
+ if PY3:
+ value = value.encode('utf-8')
len_value = len(value)
dest_ptr = SaVoidPtr()
rc = ntf.saNtfPtrValAllocate(ntf_handle, len_value + 1, dest_ptr,
@@ -300,14 +303,10 @@ class NtfProducer(ntf.NtfAgent):
"""
header.eventType.contents.value = self.ntf_info.event_type
- header.notificationObject.contents.value = \
- self.ntf_info.notification_object
- header.notificationObject.contents.length = \
- len(self.ntf_info.notification_object)
+ header.notificationObject[0] = \
+ SaNameT(self.ntf_info.notification_object)
- header.notifyingObject.contents.value = self.ntf_info.notifying_object
- header.notifyingObject.contents.length = \
- len(self.ntf_info.notifying_object)
+ header.notifyingObject[0] = SaNameT(self.ntf_info.notifying_object)
header.notificationClassId.contents.vendorId = \
self.ntf_info.ntf_class_id.vendorId
@@ -318,10 +317,13 @@ class NtfProducer(ntf.NtfAgent):
header.eventTime.contents.value = self.ntf_info.event_time
- header.lengthAdditionalText = len(self.ntf_info.additional_text)
+ additional_text = self.ntf_info.additional_text
+ if PY3:
+ additional_text = self.ntf_info.additional_text.encode('utf-8')
+ header.lengthAdditionalText = len(additional_text)
ctypes.memmove(header.additionalText,
- self.ntf_info.additional_text,
- len(self.ntf_info.additional_text) + 1)
+ additional_text,
+ len(additional_text) + 1)
if self.ntf_info.additional_info:
for i, add_info in enumerate(self.ntf_info.additional_info):
diff --git a/src/imm/tools/immxml-merge b/src/imm/tools/immxml-merge
index 3a9edda9b..9a03d3a9b 100755
--- a/src/imm/tools/immxml-merge
+++ b/src/imm/tools/immxml-merge
@@ -28,9 +28,19 @@ from datetime import datetime
from baseimm import BaseOptions, BaseImmDocument, trace, retrieve_file_names,
\
print_info_stderr, abort_script, verify_input_file_read_access
+PY3 = True if sys.version_info[0] == 3 else False
+
+
+def bytes_to_str(bytes_obj, encoding):
+ """ Convert bytes object to string in python3 """
+ if PY3 and isinstance(bytes_obj, bytes):
+ return bytes_obj.decode(encoding)
+
+ return bytes_obj
+
class Options(BaseOptions):
- """ immxml-merge options"""
+ """ immxml-merge options """
keepCommentElements = False
ignoreVariants = False
ignoreMissingClass = False
@@ -366,19 +376,25 @@ class MergedImmDocument(BaseImmDocument):
heading = "<?xml version=\"1.0\"?>"
file_object.write(heading)
- file_object.write(
- self.imm_content_element.toxml(encoding).replace("/>", ">") + "\n")
+ string = bytes_to_str(self.imm_content_element.toxml(encoding),
+ encoding)
+ file_object.write(string.replace("/>", ">") + "\n")
for class_element_tuple in self.classList:
if Options.keepCommentElements:
for textNode in class_element_tuple[1][0]:
- file_object.write(textNode.toxml(encoding) + "\n")
- file_object.write(class_element_tuple[1][1].toxml(encoding) + "\n")
+ string = bytes_to_str(textNode.toxml(encoding), encoding)
+ file_object.write(string + "\n")
+ string = bytes_to_str(class_element_tuple[1][1].toxml(encoding),
+ encoding)
+ file_object.write(string + "\n")
for object_element_tuple in self.objectList:
if Options.keepCommentElements:
for textNode in object_element_tuple[1][0]:
- file_object.write(textNode.toxml(encoding) + "\n")
- file_object.write(
- object_element_tuple[1][1].toxml(encoding) + "\n")
+ string = bytes_to_str(textNode.toxml(encoding), encoding)
+ file_object.write(string + "\n")
+ string = bytes_to_str(object_element_tuple[1][1].toxml(encoding),
+ encoding)
+ file_object.write(string + "\n")
file_object.write("</imm:IMM-contents>")
file_object.close()
trace("Stored resulting xml document in tmp file: %s",