Écrit par

Sales Engineer at InterSystems
Article Guillaume Rongier · 4 h il y a 7m read

Manipuler les globals InterSystems IRIS de façon Pythonic avec `iris-global-reference`

Les globals InterSystems IRIS sont un des points forts de la plateforme : ils permettent de stocker des données hiérarchiques avec une structure extrêmement directe, ordonnée et performante. Mais lorsqu'on travaille depuis Python, leur manipulation peut parfois sembler plus proche d'une API bas niveau que des habitudes naturelles du langage.

Le projet iris-global-reference propose une couche Python au-dessus des globals IRIS. L'objectif est simple : rendre l'accès aux globals plus lisible, plus idiomatique et plus facile à intégrer dans du code Python moderne, sans masquer le modèle hiérarchique sous-jacent.

Tags suggérés : InterSystems IRIS, Python, Embedded Python, Globals, JSON

Pourquoi ce projet ?

En ObjectScript, les globals sont naturels :

set ^demo("players",1)="Babe Ruth"
set ^demo("players",2)="Cy Young"

En Python, on a souvent envie d'écrire quelque chose de plus proche d'un dictionnaire :

team["players", "1"] = "Babe Ruth"
print(team["players"]["1"])

C'est précisément ce que fournit iris-global-reference avec la classe GlobalReference.

Le projet vise plusieurs usages :

  • manipuler des globals IRIS avec une syntaxe Pythonic ;
  • parcourir facilement une arborescence de globals ;
  • convertir des globals vers des dictionnaires Python ou du JSON ;
  • importer des dictionnaires ou du JSON dans IRIS ;
  • utiliser la même API en Embedded Python ou depuis une connexion distante ;
  • encapsuler les opérations courantes comme set, get, kill, $ORDER, $QUERY et les transactions.

Installation

Le package est disponible via pip :

pip install iris-global-reference

Pour l'utiliser directement depuis un terminal Python IRIS, il est aussi possible de l'installer dans le répertoire Python de l'instance :

pip install iris-global-reference --target=<mgr_dir>/python

Premier exemple

Voici un exemple minimal avec un global ^demo :

from iris_global import GlobalReference

team = GlobalReference("^demo")
team.kill()

team.set((), "Baseball")
team["name"] = "Boston Red Sox"
team.set(("players", "1"), "Babe Ruth")
team.set(["players", "2"], "Cy Young")
team["players", "3"] = "Ted Williams"

print(team.get(()))
print(team["name"])
print(team["players"]["1"])

La même référence accepte plusieurs formes de subscripts : chaîne, liste ou tuple. Cela permet d'utiliser l'API selon le style le plus pratique pour le code appelant.

Une API proche des dictionnaires Python

GlobalReference expose des méthodes explicites :

team.set(("players", "1"), "Babe Ruth")
print(team.get(("players", "1")))
team.kill(("players", "1"))

Mais elle supporte aussi les opérations Python habituelles :

team["players", "1"] = "Babe Ruth"

if ("players", "1") in team:
    print(team["players"]["1"])

del team["players", "1"]

Cette syntaxe est utile pour écrire du code applicatif plus naturel, tout en restant aligné avec le modèle des globals.

Parcourir un global

Le projet fournit plusieurs méthodes d'itération :

for key in team.keys():
    print(key)

for value in team.values():
    print(value)

for key, value in team.items():
    print(key, value)

On peut également contrôler le parcours :

for subscript in team.subscripts(("players",), children_only=True):
    print(subscript, team.get(subscript))

Pour les développeurs habitués à ObjectScript, order() et query() donnent accès à des comportements proches de $ORDER et $QUERY :

print(team.order(("players", "")))
print(team.query(("players",)))

Exporter un global en dictionnaire ou en JSON

Un des intérêts du projet est de faciliter les allers-retours entre globals IRIS et structures Python.

data = team.to_dict()
print(data)

Exemple de résultat :

{
    None: "Baseball",
    "name": "Boston Red Sox",
    "players": {
        "1": "Babe Ruth",
        "2": "Cy Young",
        "3": "Ted Williams"
    }
}

La clé None représente la valeur du nœud courant. C'est nécessaire parce qu'un nœud de global IRIS peut avoir à la fois une valeur et des descendants, alors qu'un dictionnaire Python représente généralement soit une valeur, soit un sous-dictionnaire.

Le même contenu peut être exporté en JSON :

json_data = team.to_json()
print(json_data)

En JSON, la valeur du noeud courant est représentée par défaut avec la clé _ :

{
    "_": "Baseball",
    "name": "Boston Red Sox",
    "players": {
        "1": "Babe Ruth",
        "2": "Cy Young",
        "3": "Ted Williams"
    }
}

L'import fonctionne dans l'autre sens :

team.from_dict({
    None: "Baseball",
    "name": "Boston Red Sox",
    "players": {
        "1": "Babe Ruth",
        "2": "Cy Young"
    }
})

Et pour le JSON :

team.from_json("""
{
    "_": "Baseball",
    "name": "Boston Red Sox",
    "players": {
        "1": "Babe Ruth",
        "2": "Cy Young"
    }
}
""")

Embedded Python ou connexion distante

L'API peut être utilisée depuis Embedded Python, sans fournir de connexion :

from iris_global import GlobalReference

team = GlobalReference("^demo")
team["name"] = "Boston Red Sox"

Elle peut aussi être utilisée depuis un programme Python externe avec une connexion native IRIS :

import iris
from iris_global import GlobalReference

conn = iris.connect("localhost", 1972, "USER", "SuperUser", "SYS")
team = GlobalReference("^demo", connection=conn)

team["name"] = "Boston Red Sox"
print(team["name"])

Le projet cible l'utilisation de la connexion native fournie par iris.connect(...).

Transactions

Les transactions sont exposées via un context manager Python :

from iris_global import GlobalReference

team = GlobalReference("^demo")

with team.transaction():
    team["name"] = "Boston Red Sox"
    team["players", "1"] = "Babe Ruth"

Si le bloc se termine correctement, la transaction est validée. En cas d'exception, elle est annulée.

La classe peut aussi être utilisée directement avec with :

with GlobalReference("^demo") as team:
    team["name"] = "Boston Red Sox"

Support expérimental des tableaux

Les globals IRIS n'ont pas de notion native de tableau au sens JSON ou Python. Pour permettre l'import et l'export de listes, le projet utilise une convention de sérialisation.

Par exemple :

gref = GlobalReference("^demo")
gref.from_dict({
    "name": "example",
    "numbers": [1, 2, 3]
})

print(gref.to_dict())

Le tableau est stocké dans le global avec un préfixe interne, par défaut __array__, puis reconstruit en liste Python lors de l'export. Cette partie est encore expérimentale, mais elle rend déjà plus pratique l'échange avec des structures JSON.

Afficher le contenu comme un ZWRITE

Pour déboguer ou vérifier rapidement la structure stockée, la méthode zw() retourne une représentation proche de ZWRITE :

print(team.zw())

Exemple :

^demo="Baseball"
^demo("name")="Boston Red Sox"
^demo("players","1")="Babe Ruth"
^demo("players","2")="Cy Young"

C'est pratique lorsqu'on veut comparer le résultat Python avec ce que l'on aurait écrit ou inspecté côté ObjectScript.

Comparaison rapide avec les API natives

L'objectif du projet n'est pas de remplacer les API natives IRIS, mais d'ajouter une couche de confort pour les cas où l'on écrit principalement du Python.

Par exemple, avec iris-global-reference :

global_reference.set(("name", 1), "Boston Red Sox")
value = global_reference.get(("name", 1))

Avec une API native, l'ordre des arguments et la gestion des subscripts peuvent être différents. Cette librairie homogénéise l'usage autour d'une convention Python : le chemin du nœud d'abord, la valeur ensuite.

Quand utiliser ce projet ?

iris-global-reference est particulièrement utile si vous :

  • développez en Embedded Python avec InterSystems IRIS ;
  • écrivez des scripts Python qui doivent lire ou alimenter des globals ;
  • voulez exposer des données de globals sous forme JSON ;
  • voulez manipuler des structures hiérarchiques IRIS avec des dictionnaires Python ;
  • voulez prototyper rapidement sans écrire beaucoup de code ObjectScript ;
  • cherchez une API plus lisible pour les opérations courantes sur les globals.

Roadmap

La roadmap actuelle mentionne notamment :

  • un support plus avancé des tableaux ;
  • un support plus complet des données binaires ;
  • des types IRIS comme listbuild, vector, PVA ou bit ;
  • le support de variables multidimensionnelles.

Tester le projet

Le dépôt contient une suite de tests. Pour l'exécuter :

python -m pytest

Conclusion

iris-global-reference est une petite librairie, mais elle répond à un besoin concret : rendre les globals IRIS plus agréables à manipuler depuis Python.

Elle conserve les opérations fondamentales du modèle IRIS, tout en ajoutant une expérience proche des dictionnaires Python, des conversions JSON pratiques, des itérateurs, et une utilisation possible en Embedded Python comme en connexion distante.

Pour les développeurs qui travaillent à l'intersection d'InterSystems IRIS et de Python, c'est un outil simple à essayer et facile à intégrer dans des scripts, des prototypes ou des applications plus structurées.

Liens :

Comments