Artículo
· 15 mar, 2023 Lectura de 3 min

Cómo llamar métodos de clase con la API nativa para Python

El SDK nativo para Python de InterSystems es una interfaz ligera para las APIs de InterSystems IRIS, que anteriormente solo estaba disponible mediante ObjectScript.

Estoy especialmente interesado en la capacidad de llamar a los métodos de ObjectScript, a los métodos de clase, para ser más preciso. Esto funciona, y funciona muy bien, pero de manera predeterminada, las llamadas únicamente admiten argumentos escalares: strings, booleanos, enteros y flotantes.

Pero si lo que quieres es:
- Pasar o devolver estructuras, como diccionarios (dicts) o listas
- Pasar o devolver streams

Necesitarás escribir algún código adhesivo (glue code) o aprovechar este proyecto (se instala mediante pip install edpy). El paquete edpy te da una estructura sencilla:

call(iris, class_name, method_name, args)

que te permite llamar a cualquier método de ObjectScript y obtener los resultados.

Se importa así:

from edpy import iris

call acepta 4 argumentos necesarios:
- iris - hace referencia a un objeto de IRIS establecido
- class_name - la clase de IRIS que debe llamarse
- method_name - el método de IRIS que debe llamarse
- args - lista con 0 o más argumentos

Argumentos

Cada argumento puede ser alguno de los siguientes:

  • string (de cualquier longitud, si es mayor que $$$MaxStringLength o 3641144 símbolos, se convertirá automáticamente en un stream)
  • booleano
  • entero
  • flotante
  • dict (se convierte en un objeto dinámico)
  • lista o tupla (se convierte en una matriz dinámica)

Los argumentos de dict, lista y tupla pueden contener otros dicts, listas y tuplas de forma recurrente (mientras dure la memoria).

Valor devuelto

A cambio, esperamos o un objeto/matriz dinámico o una string/stream JSON. En ese caso, edpy primero lo convertiría en un string Python y, si fuera posible, lo interpretaría como un dict o lista Python. De lo contrario, el resultado sería devuelto tal cual.

Eso es todo lo que debemos saber por el momento, pero permíteme dar algunos ejemplos de métodos ObjectScript y cómo llamarlos usando esta función de Python.

Ejemplo 1: Pong

ClassMethod Test(arg1, arg2, arg3) As %DynamicArray
{
    return [(arg1), (arg2), (arg3)]
}

Se llama con:

>>> iris.call(iris_native, "User.Py", "Test", [1, 1.2, "ABC"])
[1, 1.2, 'ABC']

El resultado no es ninguna sorpresa. Los argumentos se vuelven a empaquetar en una matriz y se devuelven.

Ejemplo 2: Propiedades

ClassMethod Test2(arg As %DynamicObject) As %String
{
    return arg.Prop
}

Se llama así:

>>> iris.call(iris_native, "User.Py", "Test2", [{"Prop":123}])
123

Para una invocación más embebida:

>>> iris.call(iris_native, "User.Py", "Test2", [{"Prop":{"Prop2":123}}])
{'Prop2': 123}

No hay ningún problema si una propiedad es demasiado larga: se utilizarán streams para enviarla y/o devolverla a IRIS:

ret = iris.call(iris_native, "User.Py", "Test2", [{"Prop":"A" * 10000000}])
>>> len(ret)
10000000

Si necesitas streams garantizados en el lado de InterSystems IRIS, puedes usar %Get:

set stream = arg.%Get("Prop",,"stream")

Si el stream está codificado en base64, puedes descodificarlo automáticamente mediante:

set stream = arg.%Get("Prop",,"stream<base64")

Ejemplo 3: String o stream

ClassMethod Test3(arg As %Stream.Object) As %String
{
    set file = ##class(%Stream.FileCharacter).%New()
    set file.TranslateTable = "UTF8"
    set filename = ##class(%File).ManagerDirectory() _ "test.txt"
    do file.LinkToFile(filename)
    if $isObject(arg) {
        set sc = file.CopyFromAndSave(arg)
    } else {
        do file.Write(arg)
        set sc = file.%Save()
    }
    if $$$ISERR(sc) {
        set jsonret = {"status":0, "payload":($system.Status.GetErrorText(sc))}
    } else {
        set jsonret = {"status":1}
    }
    quit jsonret.%ToJSON()
}

Aquí escribimos o un string o un stream para <mgr>test.txt.

>>> iris.call(iris_native, "User.Py", "Test3", ["&#x1f60a;"])
{'status': 1}

Nota: en todos los ejemplos de código "&# x1f642;" se introduce como 😊.

Y si abro el archivo veré un 😊 y no dos ??, de esta forma conservamos el cifrado.

>>> iris.call(iris_native, "User.Py", "Test3", ["&#x1f642;" * 10000000])
{'status': 1}

Por ser breve, omitiré el archivo resultante, pero allí está.

Por último, al pasar dentro un objeto dinámico o una matriz, se puede evitar por completo la dicotomía string/stream, incluso si no sabes si la propiedad sería más corta o más larga que el límite del string. En ese caso, siempre puedes obtener la propiedad de la que dudas como un stream.

Ejemplo 4: Streams de retorno

ClassMethod Test4(arg As %DynamicArray) As %String
{
    return arg.%Get(0)
}

Así es como se ve:

>>> ret = iris.call(iris_native, "User.Py", "Test4", [["&#x1f60a;" * 10000000]])
>>> len(ret)
10000000
>>> ret[:5]
'&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;'

Una cosa más

También hay una función get_iris(ip="localhost", port=1972, namespace="USER", username="_SYSTEM", password="SYS") que te permitirá obtener un objeto funcional de IRIS. Este es un ejemplo completo, por si quieres comprobarlo por ti mismo:

Primero carga la clase User.Py e instala la librería de Phyton edpy:

pip install edpy

Y después en la llamada en Python:

from edpy import iris
iris_native = iris.get_iris()
iris.call(iris_native, "User.Py", "Test",  [1, 1.2, "ABC"])
iris.call(iris_native, "User.Py", "Test2", [{"Prop":123}])
iris.call(iris_native, "User.Py", "Test2", [{"Prop":{"Prop2":123}}])
ret2 = iris.call(iris_native, "User.Py", "Test2", [{"Prop":"A" * 10000000}])
iris.call(iris_native, "User.Py", "Test3", ["&#x1f60a;"])
iris.call(iris_native, "User.Py", "Test3", ["&#x1f60a;" * 10000000])
ret4 = iris.call(iris_native, "User.Py", "Test4", [["&#x1f60a;" * 10000000]])

Conclusión

El SDK nativo para Python es una potente herramienta, que proporciona un acceso completo y sin restricciones a InterSystems IRIS. Espero que este proyecto pueda ahorrarte algo de tiempo cuando preparas las llamadas a InterSystems IRIS. ¿Hay alguna combinación de argumentos que no esté soportada? Si es así, comparte en los comentarios cómo realizas las llamadas.

Enlaces

Comentarios (0)2
Inicie sesión o regístrese para continuar