The python 'dict' object is ubiquitous when interacting with python modules, functions and classes.
The process to create a python DICT object using the U2 BASIC Python API is, well, interesting:
- Create a LIST containing just the 'name' and 'value' for the DICT entry
- Create a TUPLE from the list
- Append the TUPLE to another LIST that will be used to create the DICT
- When the LIST of TUPLE objects is completed, create a DICT using the LIST of TUPLES
This all works ok for strings and numbers, but I cannot get a boolean True or False value to use in the tuple.
I either get an integer value of 1, or 'None'.
This is the code I have tested so far, trying to get a python True object/value:
** Attempting to create a python True object using the PyBASIC API
pmo.BUILTINS = PyImport("builtins")
if len(@PYEXCEPTIONTYPE) then gosub PY.BADNESS
* Using CallMethod to run the "bool(x)" command
test1 = PyCallMethod( pmo.BUILTINS, "bool", (-1))
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test1', test1)
* Using CallMethod to run the "True" value
test2 = PyCallMethod( pmo.BUILTINS, "True")
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test2', test2)
* Create callable PyBobject for bool()
py_bool = PyGetAttr( pmo.BUILTINS, "bool")
if len(@PYEXCEPTIONTYPE) then gosub PY.BADNESS
* Create True using the __new__() method
test3 = PyCallMethod( py_bool, "__new__", (1))
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test3', test3)
* Use the GetAttr method to get the True attribute
test4 = PyGetAttr( pmo.BUILTINS, "True")
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test4', test4)
stop
PY.BADNESS:
crt " EXCEPTION TYPE = " :@PYEXCEPTIONTYPE
crt " EXCEPTION MESSAGE = " :squote(@PYEXCEPTIONMSG)
crt " EXCEPTIONTRACEBACK = " :@PYEXCEPTIONTRACEBACK
stop
When I run this all I get is this result:
>RUN GDS.BP TEST.PY.TRUE
test1 1
test2 None
test3 None
test4 1
>
Does anyone have any thoughts on how I can correctly create a True or False python value/object using the U2 BASIC Python API functions?
Whilst I could create python code to do this, I am trying to avoid the need to pre-deploy the python source as this logic is intended to be used as part of our python deployment processing (otherwise I have to deploy code so I can test the installation context to see if I need to deploy code ...).
------------------------------
Gregor Scott
Software Architect
Pentana Solutions Pty Ltd
Mount Waverley VIC AU
------------------------------
Hi Gregor
Not sure about the first half of your question, you can create and populate a dict object directly:
b = PyImport("builtins")
dict = PyCallMethod(b,"dict")
ok = PyCallMethod(dict,"__setitem__","hello","world")
ok = PyCallMethod(dict,"__repr__")
Crt ok
{'hello': 'world'}
However, I can't find a way to send a bool into the __setitem__ without it being coerced into a 1 or zero, either. I suspect it is the passing mechanism not the construction of the bool i.e.
PyTrue = PyCallMethod(b,"bool",1)
Ok = PyCallMethod(dict,"__setitem__","atrue",PyTrue)
Ok = PyCallMethod(dict,"__repr__")
Crt Ok
{'hello': 'world', 'atrue': 1}
------------------------------
Brian Leach
Director
Brian Leach Consulting
Chipping Norton GB
------------------------------
Hi Gregor
Not sure about the first half of your question, you can create and populate a dict object directly:
b = PyImport("builtins")
dict = PyCallMethod(b,"dict")
ok = PyCallMethod(dict,"__setitem__","hello","world")
ok = PyCallMethod(dict,"__repr__")
Crt ok
{'hello': 'world'}
However, I can't find a way to send a bool into the __setitem__ without it being coerced into a 1 or zero, either. I suspect it is the passing mechanism not the construction of the bool i.e.
PyTrue = PyCallMethod(b,"bool",1)
Ok = PyCallMethod(dict,"__setitem__","atrue",PyTrue)
Ok = PyCallMethod(dict,"__repr__")
Crt Ok
{'hello': 'world', 'atrue': 1}
------------------------------
Brian Leach
Director
Brian Leach Consulting
Chipping Norton GB
------------------------------
Hi Brian,
Thanks for the confirmation on the "True" object creation - always nice to know it is not just me!
My initial approach to the DICT creation was to use a "pythonic" approach as much as possible.
The dunder __setitem__ function is so much simpler than my approach (and more performant) I think I will consider using more of the "private" python functions wherever possible.
------------------------------
Gregor Scott
Software Architect
Pentana Solutions Pty Ltd
Mount Waverley VIC AU
------------------------------
Hi Gregor
Not sure about the first half of your question, you can create and populate a dict object directly:
b = PyImport("builtins")
dict = PyCallMethod(b,"dict")
ok = PyCallMethod(dict,"__setitem__","hello","world")
ok = PyCallMethod(dict,"__repr__")
Crt ok
{'hello': 'world'}
However, I can't find a way to send a bool into the __setitem__ without it being coerced into a 1 or zero, either. I suspect it is the passing mechanism not the construction of the bool i.e.
PyTrue = PyCallMethod(b,"bool",1)
Ok = PyCallMethod(dict,"__setitem__","atrue",PyTrue)
Ok = PyCallMethod(dict,"__repr__")
Crt Ok
{'hello': 'world', 'atrue': 1}
------------------------------
Brian Leach
Director
Brian Leach Consulting
Chipping Norton GB
------------------------------
I revised my test code to check the type of variable being returned.
Whilst on UV 11.35 the descrinfo() function does not explicitly recognise a PYOBJECT it does return a "-1" when the type of variable cannot be determined.
The updated code looks like this
** Attempting to create a python True object using the PyBASIC API
pmo.BUILTINS = PyImport("builtins")
if len(@PYEXCEPTIONTYPE) then gosub PY.BADNESS
* Using CallMethod to run the "bool(x)" command
test1 = PyCallMethod( pmo.BUILTINS, "bool", (-1))
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test1', test1)
crt "descrinfo(1,test1)=":descrinfo(1,test1)
* Using CallMethod to run the "True" value
test2 = PyCallMethod( pmo.BUILTINS, "True")
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test2', test2)
crt "descrinfo(1,test2)=":descrinfo(1,test2)
* Create callable PyBobject for bool()
py_bool = PyGetAttr( pmo.BUILTINS, "bool")
if len(@PYEXCEPTIONTYPE) then gosub PY.BADNESS
crt "descrinfo(1,py_bool)=":descrinfo(1,py_bool)
* Create True using the __new__() method
test3 = PyCallMethod( py_bool, "__new__", (1))
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test3', test3)
crt "descrinfo(1,test3)=":descrinfo(1,test3)
* Use the GetAttr method to get the True attribute
test4 = PyGetAttr( pmo.BUILTINS, "True")
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test4', test4)
crt "descrinfo(1,test4)=":descrinfo(1,test4)
* Try the PyCall api
test5 = PyCall( py_bool, (-1))
rslt = PyCallMethod( pmo.BUILTINS, "print", 'test5', test5)
crt "descrinfo(1,test5)=":descrinfo(1,test5)
stop
PY.BADNESS:
crt " EXCEPTION TYPE = " :@PYEXCEPTIONTYPE
crt " EXCEPTION MESSAGE = " :squote(@PYEXCEPTIONMSG)
crt " EXCEPTIONTRACEBACK = " :@PYEXCEPTIONTRACEBACK
stop
This now produces this output:
>TEST.PY.TRUE
test1 1
descrinfo(1,test1)=1
test2 None
descrinfo(1,test2)=-1
descrinfo(1,py_bool)=-1
test3 None
descrinfo(1,test3)=-1
test4 1
descrinfo(1,test4)=1
test5 1
descrinfo(1,test5)=1
>
The variable type for both test2 and test3 is "-1" leading me to think they are the only PYOBJECT variables returned in the test code.
Their value when printed using the API call is "None" which is a pythonic value, but wrong.
So it seems that the U2 BASIC Python API has issues with the bool class being passed in/out of the API functions.
------------------------------
Gregor Scott
Software Architect
Pentana Solutions Pty Ltd
Mount Waverley VIC AU
------------------------------