Hello Community,
In this article, I will outline and illustrate the process of implementing ObjectScript within embedded Python. This discussion will also reference other articles related to embedded Python, as well as address questions that have been beneficial to my learning journey.
As you may know, the integration of Python features within IRIS has been possible for quite some time. This article will focus on how to seamlessly incorporate ObjectScript with embedded Python.
Essentially, embedded Python serves as an extension that allows for independent writing and execution. It enables the seamless integration of Python code with ObjectScript and vice versa, allowing both to run within the same context. This functionality significantly enhances the capabilities of your implementation.
To begin, you must specify the language for your Python code within the class definition by using the "language" keyword [language = "python"]. Once this is done, you are prepared to write your Python code.
import iris -
The iris package is a vital Python library that facilitates communication with InterSystems' native API classes, routines, globals, and SQL. This package is readily available by default. Anyway It is necessary to import this package at the beginning of your python code if you're going to interact with IRIS.
Few important notes before writing
You can use python special variable __name__ to refer the classname inside the class definition.
Use _ for %Methods ex: %New == _New , %OpenId == _OpenId
Let's begin
Class members implementation in Embedded python
1. Objects and Properties
This section is essential as it will cover the process of initializing a new object, altering the values of existing objects, and configuring properties in both static and dynamic contexts. Create your own class definition and use the simple literal properties
1.1 initialize new Object / Modify existing object
Use _New for initiate new object and _OpenId(id) for edit the existing object
ClassMethod SaveIRISClsObject() [ Language = python ]
{
#this method calls the %OnNew callback method and get the object
import iris
try:
iris_obj = iris.cls(__name__)._New()
if not iris.cls(__name__).IsObj(iris_obj):
#IsObj is the objectscript wrapper method : which contains $Isobject()
raise ReferenceError('Object Initlize Error')
except ReferenceError as e:
print(e)
return
#set the object properties and save the values
iris_obj.Name = 'Ashok'
iris_obj.Phone = 9639639635
status = iris_obj._Save()
print(status)
return status
}
PythonPython
1.2 Accessing properties
Prior to commencing the property section, it is important to note that the IRIS data type differs from Python data types, and therefore, IRIS collection data types cannot be utilized directly within Python. To address this, InterSystems has offered a comprehensive solution for converting IRIS data types into Python-compatible formats such as lists, sets, and tuples. This can be achieved by importing the "builtins" module within the IRIS code base, utilizing the class methods ##class(%SYS.Python).Builtins() or by setting builtins = ##class(%SYS.Python).Import("builtins"). I'll cover this in upcoming sections.
So, I use this method to convert the $LB properties into python list for accessing the properties at runtime in python
LEARNING>zw pyList
pyList=5@%SYS.Python ; ['Name', 'Phone', 'City'] ; <OREF>
ClassMethod GetProperties() [Language = objectscript]
{
set pyList = ##class(%SYS.Python).ToList($LB("Name","Phone","City"))
do ..pyGetPropertiesAtRunTime(pyList)
}
ClassMethod pyGetPropertiesAtRunTime(properties) [ Language = python ]
{
import iris
iris_obj = iris.cls(__name__)._OpenId(1)
for prop in properties:
print(getattr(iris_obj,prop))
}
ObjectScriptObjectScript
1.3 Set properties at runtime.
I utilize this python dictionary to designate my property as a key and, with the corresponding property values serving as the values within that dictionary. You may refer to the code provided below and the community post regarding this property set.
ClassMethod SetProperties()
{
Set pyDict = ##class(%SYS.Python).Builtins().dict()
do pyDict.setdefault("Name1", "Ashok kumar")
do pyDict.setdefault("Phone", "9639639635")
do pyDict.setdefault("City", "Zanesville")
Set st = ..pySetPropertiesAtRunTime(pyDict)
}
ClassMethod pySetPropertiesAtRunTime(properties As %SYS.Python) [ Language = python ]
{
import iris
iris_obj = iris.cls(__name__)._New()
for prop in properties:
setattr(iris_obj, prop,properties[prop])
status = iris_obj._Save()
return status
}
ObjectScriptObjectScript
1.4 Object share context
As previously stated, both Python and ObjectScript operate within the same memory context and share objects. This implies that you can create or open an object in the InCache class and subsequently set or retrieve it in the Python class.
ClassMethod ClassObjectAccess() [Language = objectscript]
{
Set obj = ..%OpenId(1)
Write obj.PropAccess(),! ; prints "Ashok kumar"
Do obj.DefineProperty("test")
Write obj.PropAccess() ; prints "test"
}
Method PropAccess() [ Language = python ]
{
return self.Name
}
Method DefineProperty(name) [ Language = python ]
{
self.Name = name
}
ObjectScriptObjectScript
2. Parameters
Get the parameter arbitrary key value pair by using the _GetParameter. Refer the useful community post
ClassMethod GetParam(parameter = "MYPARAM") [ Language = python ]
{
import iris
value = iris.cls(__name__)._GetParameter(parameter)
print(value)
}
PythonPython
3. Class Method and Methods
3.1 Class Method
The invocation of class methods and functions is highly beneficial for executing the object script code.
Invoke the class method as a static call ex: Do ..Test()
ClassMethod InvokeStaticClassMethods(clsName = "MyLearn.EmbeddedPython") [ Language = python ]
{
import iris
print(iris.cls(clsName).Test())
# print(iris.cls(__name__).Test())
}
PythonPython
Invoke the Class method at runtime Set method="Test" Do $ClassMethod(class, method, args...)
ClassMethod InvokeClassMethodsRunTime(classMethod As %String = "Test") [ Language = python ]
{
import iris
clsMethodRef = getattr(iris.cls(__name__), classMethod) # will return the reference of the method
print(clsMethodRef())
}
PythonPython
3.2 Methods
Invoke the instance methods are same as "object script" format. In the below code I've initiate the object first and call the instance method with parameters.
ClassMethod InvokeInstanceMethodWithActualParameters() [ Language = python ]
{
import iris
obj = iris.cls(__name__)._New()
print(obj.TestMethod(1,2,4))
}
PythonPython
3.3 Pass arguments by value and reference b/w python and objectscript
Basically passing the arguments are inevitable between the functions and the same will remain between ObjectScript and python
3.4 Pass by value - It's as usual pass by value
ClassMethod passbyvalfromCOStoPY()
{
Set name = "test", dob= "12/2/2002", city="chennai"
Do ..pypassbyvalfromCOStoPY(name, dob, city)
}
ClassMethod pypassbyvalfromCOStoPY(name As %String, dob As %String, city As %String) [ Language = python ]
{
print(name,' ',dob,' ',city)
}
/// pass by value from python to object script
ClassMethod pypassbyvalfromPY2COS() [ Language = python ]
{
import iris
name = 'test'
dob='12/2/2002'
city='chennai'
iris.cls(__name__).passbyvalfromPY2COS(name, dob, city)
}
ClassMethod passbyvalfromPY2COS(name As %String, dob As %String, city As %String)
{
zwrite name,dob,city
}
ObjectScriptObjectScript
3.5 Pass by reference- Unlike the pass by value. Since Python does not support call by reference natively, so, you need to use the iris.ref()
in python code to make it the variable as a reference. refer the reference. To the best of my knowledge, there are no effects on the object script side regarding pass-by-reference variables, even when these variables are modified in Python. Consequently, Python variables will be affected by this pass-by-reference mechanism when the methods of the object script are invoked
ClassMethod pypassbyReffromPY2COS() [ Language = python ]
{
import iris
name='python'
dob=iris.ref('01/01/1991')
city = iris.ref('chennai')
print('before COS ',name,' ',dob.value,' ',city.value)
#pass by reference of dob, city
iris.cls('MyLearn.EmbeddedPythonUtils').passbyReffromPY2COS(name, dob, city)
print('after COS ',name,' ',dob.value,' ',city.value)
}
ClassMethod passbyReffromPY2COS(name, ByRef dob, ByRef city)
{
Set name="object script", dob="12/12/2012", city="miami"
}
// output
LEARNING>do ##class(MyLearn.EmbeddedPythonUtils).pypassbyReffromPY2COS()
before COS python 01/01/1991 chennai
after COS python 12/12/2012 miami
ObjectScriptObjectScript
3.5 **kwargs- There is an additional support for passing the python keyword arguments (**kwargs) from object script. Since InterSystems IRIS does not have the concept of keyword arguments, you have to create a %DynamicObject to hold the keyword/value pairs and pass the values as syntax Args...
I have created the dynamicObject { "name": "ashok", "city": "chennai"}
and set the required key-value pairs in it and eventually pass to the python code.
ClassMethod KWArgs()
{
set kwargs={ "name": "ashok", "city": "chennai"}
do ..pyKWArgs(kwargs...)
}
ClassMethod pyKWArgs(name, city, dob = "") [ Language = python ]
{
print(name, city, dob)
}
// output
LEARNING>do ##class(MyLearn.EmbeddedPythonUtils).KWArgs()
ashok chennai
ObjectScriptObjectScript
I will cover the global, routines and SQL in next article
Thanks! A great summary!