Question
· Aug 14

ObjectScript ClassMethod when called from Python method always returns empty string

If anyone has experience debugging Embedded Python or has insight into why an ObjectScript method when called from a Python method would not work but would work when called directly via ObjectScript or in a Python shell, your help would be appreciated! 

We have an ObjectScript ClassMethod called GetTemplateString() which takes in a templateName of String type and uses the template name to get the template object, access the Code, and read the code into a templateString. The string version of the Code is returned.

ClassMethod GetTemplateString(templateName As %String) As %String
{
    set template = ##class(%Library.RoutineMgr).%OpenId(templateName)
    set templateString = template.Code.Read()
    return templateString
}

This method works as expected when called directly from ObjectScript in an IRIS terminal and also works when called directly from an IRIS terminal in the Python shell. In both cases the expected string value of the template Code contents is returned.

However, we need to call the GetTemplateString method from inside a Language = python type ClassMethod. When we call the method from within the Python class using iris.cls() an empty string is the returned value for templateString. 

ClassMethod MergeInternal(templateName As %String, templateString As %String) As %Stream.Object [ Language = python ]
{
    import iris
    class IRISLoader:
        def load_text(self, name):
            # for some reason, when called from a Python method the below method always returns an empty string.
            templateString = iris.cls('pkg.isc.airspeed.API').GetTemplateString(name)
            return templateString
        def load_template(self, name):
            template = Template(self.load_text(name), filename=name)
            return template
...
}

In debugging, we have confirmed using CodeGetSwizzled(1) that the Code has been swizzled, but Code when Read() always returns an empty string when called in this way. We are unsure why this is happening when the method is called from within the python ClassMethod.

Does anyone have ideas or insight that could assist us in our debugging efforts? Thank you!

Product version: IRIS 2022.1
$ZV: IRIS for Windows (x86-64) 2022.1.2 (Build 574U)
Discussion (2)1
Log in or sign up to continue

I'm a big fan of the "old-school" debugging technique of embedding code to store interesting data into globals for later review after running the code to be debugged.

In ObjectScript, the command would look something like this:

Set ^mtempJJM("test", $i(^mtempJJM("test")) = "self=<"_self_">, "_name=<"_name_">"

And then from terminal, issuing this command:

zw ^mtempJJM("test")

One can do something similar in Python using the syntax described on the pages linked below (syntax on how to increment the global index is left to the reader 😀 ):

https://docs.intersystems.com/iris20242/csp/docbook/DocBook.UI.Page.cls?...

Global Reference API | Using Embedded Python | InterSystems IRIS Data Platform 2024.2
 

Upon further debugging, the line 

set template = ##class(%Library.RoutineMgr).%OpenId(templateName)

in the ObjectScript method returns an empty object if it could not find the expected template for templateName. For the case where we called the method from ObjectScript it was able to find the expected template and opened. When called from the Language = python method we needed to have an explicit Load of the template file prior to the method call. We resolved this by adding 

do $$$AssertStatusOK(##class(pkg.isc.airspeed.API).Load(<directory>_"_resources/trivial.vm","ck"))

prior to the call to Merge. Calling the load before the MergeInternal() method call resolved the issue.