0 Abonnés · 123 Publications

Python est un langage de programmation interprété de haut niveau pour la programmation à usage général. Créé par Guido van Rossum et publié pour la première fois en 1991, Python a une philosophie de conception qui met l'accent sur la lisibilité du code, notamment en utilisant des espaces blancs importants

Site officiel.

Documentation InterSystems sur les liaisons Python.

Article Guillaume Rongier · Oct 30, 2025 7m read

Introduction

Dans mon dernier article, j'ai présenté FHIR Data Explorer, une application de validation de concept qui connecte InterSystems IRIS, Python, et Ollama afin de permettre la recherche sémantique et la visualisation des données de soins de santé au format FHIR. Ce projet participe actuellement au concours InterSystems External Language Contest.

Dans cette suite, nous verrons comment j'ai intégré Ollama pour générer les résumés des dossiers médicaux directement à partir des données FHIR structurées stockées dans IRIS, à l'aide de modèles linguistiques locaux légers (LLM) tels que Llama 3.2:1B ou Gemma 2:2B.

L'objectif était de créer un pipeline d'IA entièrement local capable d'extraire, de formater et de présenter les dossiers médicaux des patients tout en garantissant la confidentialité et le contrôle total des données.

Toutes les données des patients utilisées dans cette démonstration proviennent de paquets FHIR, qui ont été analysés et chargés dans IRIS via le module IRIStool. Cette approche facilite la requête, la conversion et la vectorisation des données de soins de santé à l'aide d'opérations pandas familières en Python. Si vous désirez en savoir plus sur la manière dont j'ai construit cette intégration, consultez mon article précédent Création d'un référentiel vectoriel FHIR avec InterSystems IRIS et Python via le module IRIStool.

Les deux outils, IRIStool et FHIR Data Explorer sont disponibles sur InterSystems Open Exchange — et font partie de mes contributions au concours. Si vous les trouvez utiles, n'hésitez pas à voter pour eux!

1. Configuration avec Docker Compose

Pour simplifier la configuration et la rendre reproductible, tout fonctionne localement au moyen de Docker Compose.
Une configuration minimale se présente comme suit:

services:
  iris:
    container_name: iris-patient-search
    build:
      context: .
      dockerfile: Dockerfile
    image: iris-patient-search:latest  
    init: true
    restart: unless-stopped
    volumes:
      - ./storage:/durable
    ports:
      - "9092:52773"# Management Portal / REST APIs
      - "9091:1972"# SuperServer port
    environment:
      - ISC_DATA_DIRECTORY=/durable/iris
    entrypoint: ["/opt/irisapp/entrypoint.sh"]

  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    pull_policy: always
    tty: true
    restart: unless-stopped
    ports:
      - 11424:11434
    volumes:
      - ./ollama_entrypoint.sh:/entrypoint.sh
entrypoint: ["/entrypoint.sh"]

Toutes les configurations sont disponibles sur la page du projet GitHub.

2. Intégration d'Ollama dans le flux de travail

Ollama fournit une API REST locale simple pour exécuter efficacement des modèles sur le processeur, ce qui le rend idéal pour les applications de santé où la confidentialité et les performances sont importantes.

Pour connecter IRIS et Streamlit à Ollama, j'ai implémenté une classe Python légère pour transmettre les réponses de l'API Ollama:

import requests, json

classollama_request:def__init__(self, api_url: str):
        self.api_url = api_url

    defget_response(self, content, model):
        payload = {
            "model": model,
            "messages": [
                {"role": "user", "content": content}
            ]
        }
        response = requests.post(self.api_url, json=payload, stream=True)

        if response.status_code == 200:
            for line in response.iter_lines(decode_unicode=True):
                if line:
                    try:
                        json_data = json.loads(line)
                        if"message"in json_data and"content"in json_data["message"]:
                            yield json_data["message"]["content"]
                    except json.JSONDecodeError:
                        yieldf"Error decoding JSON line: {line}"else:
            yieldf"Error: {response.status_code} - {response.text}"

Cela permet de transmettre les résultats du modèle en temps réel, ce qui donne aux utilisateurs l'impression de “surveiller“ le travail de l'IA en direct dans l'interface utilisateur Streamlit.

3. Préparation des données du patient pour LLM

Avant d'envoyer quoi que ce soit à Ollama, les données doivent être compactes, structurées et pertinentes sur le plan clinique.
Pour cela, j'ai écrit une classe qui extrait et formate les données les plus pertinentes du patient (données démographiques, état de santé, observations, procédures, etc.) au format YAML, qui est à la fois compréhensible et compatible avec LLM.

Le processus simplifié est le suivant:

  1. Sélectionnez la chaîne du patient dans IRIS via pandas
  2. Extrayez les données démographiques et convertissez-les au format YAML
  3. Traitez chaque table médicale (conditions, observations, etc.)
  4. Supprimez les champs inutiles ou superflus
  5. Générez un document YAML concis utilisé comme contexte d'invite LLM.

Cette chaîne est ensuite transmise directement à l'invite LLM, formant le contexte structuré à partir duquel le modèle génère le compte rendu sommaire du patient.


4. Pourquoi limiter le nombre d'enregistrements?

Lors du développement de cette fonctionnalité, j'ai remarqué que la transmission de tous les dossiers médicaux provoquait souvent une confusion ou un biais dans les petits LLM envers les saisies plus anciennes, ce qui faisait perdre de vue les événements récents.

Pour résoudre ce problème, j'ai décidé:

  • De n'inclure qu'un nombre limité d'enregistrements par catégorie dans l' ordre chronologique inverse (plus récents en premier)
  • D'utiliser un format concis YAML au lieu du format brut JSON
  • De normaliser les types de données (horodatages, valeurs nulles, etc.) pour plus de cohérence

Cette conception aide les petits LLM à se concentrer sur les données les plus pertinentes sur le plan clinique data en évitant la “surcharge d'invites”.


💬 4. Génération du dossier médical du patient

Une fois les données au format YAML prêtes, l'application Streamlit les envoie à Ollama au moyen d'une simple invite telle que:

“Vous êtes assistant clinique. À partir des données suivantes du patient, rédigez un dossier médical concis en soulignant les pathologies pertinentes et les tendances récentes.”

Le résultat est renvoyé ligne par ligne à l'interface utilisateur, ce qui permet à l'utilisateur de surveiller la rédaction du dossier en temps réel.
Chaque modèle produit un résultat légèrement différent, même au moyen de la même invite, révélant des différences fascinantes dans le raisonnement et le style.


🧠 5. Comparaison des LLM locaux

Pour évaluer l'efficacité de cette approche, j'ai testé trois modèles ouverts et légers, disponibles via Ollama:

ModèleParamètresStyle de dossierRemarques
Llama 3.2:1B1BStructuré, factuelRésultat hautement littéral et schématique
Gemma 2:2B2BNarratif, à caractère humainLe plus cohérent et le plus sensible au contexte
Gemma 3:1B1BConcis, synthétiqueOmettant parfois certains détails, mais très compréhensible

Vous trouverez des exemples de résultats dans le  dossier GitHub suivant. Chaque dossier du patient met en évidence la manière dont la taille du modèle et le style d'entraînement influencent la structure, la cohérence et le niveau de détail du texte.

Voici une interprétation comparative de leur comportement:

  • Llama 3.2:1B reproduit généralement la structure des données mot pour mot, presque comme s'il effectuait une exportation de base de données. Ses résumés sont techniquement précis, mais ne sont pas fluides, ressemblant davantage à un rapport clinique structuré qu'à un texte naturel.
  • Gemma 3:1B offre une meilleure fluidité linguistique, mais compresse ou omet des détails mineurs. 
  • Gemma 2:2B offre le meilleur équilibre. Il organise les informations en sections significatives (conditions, facteurs de risque, recommandations de soins) tout en conservant un ton fluide.

En bref:

  • Llama 3.2:1B = précision factuelle
  • Gemma 3:1B = dossiers médicaux concis
  • Gemma 2:2B = narration cliniquement pertinente

Même sans ajustement, une curation des données et une conception des invites judicieuses permettent aux petits LLM locaux de produire des comptes rendus cliniques cohérents et pertinents dans leur contexte.


🔒 6. Pourquoi les modèles locaux sont-ils importants?

En utilisant Ollama localement, vous obtenez:

  • Un contrôle total des données — les données du patient ne disparaissent jamais de l'environnement
  • Des performances déterministes — une latence stable sur le processeur
  • Un déploiement léger — fonctionne même sans processeur graphique
  • Une conception modulaire — facile de passer d'un modèle à l'autre ou d'ajuster les invites

Cette configuration est donc idéale pour les hôpitaux, les centres de recherche ou les environnements universitaires qui souhaitent expérimenter en toute sécurité la documentation et la synthèse basées sur l'IA.


🧭 Conclusion

Cette intégration démontre que même les petits modèles locaux, lorsqu'ils sont correctement guidés par des données structurées et des invites claires, peuvent produire des dossiers médicaux utiles et proches de ceux rédigés par des humains.

Au moyen d'IRIS pour la gestion des données, Python pour convertir les données et Ollama pour la génération de texte, nous obtenons un pipeline IA entièrement local et axé sur la confidentialité pour la génération de renseignements cliniques.

1
0 18
Article Sylvain Guilbaud · Nov 6, 2025 5m read

Introduction

Dans mon article précédent, j'ai présenté le module IRIStool, qui intègre de manière transparente la bibliothèque pandas pour Python à la base de données IRIS. Je vais maintenant vous expliquer comment utiliser IRIStool pour exploiter InterSystems IRIS comme base pour une recherche sémantique intelligente dans les données de soins de santé au format FHIR.

Cet article décrit ce que j'ai fait pour créer une base de données pour mon autre projet, FHIR Data Explorer. Les deux projets sont candidats au concours InterSystems actuel, alors n'hésitez pas à voter pour eux si vous les trouvez utiles.

Ils sont disponibles sur Open Exchange:

Dans cet article, nous aborderons les sujets suivants:

  • Connexion à la base de données InterSystems IRIS via Python
  • Création d'un schéma de base de données compatible FHIR
  • Importation de données FHIR au moyen d'intégrations vectorielles pour la recherche sémantique

Conditions préalables

Installez IRIStool à partir de la page Github IRIStool et Data Manager.

1. Configuration de la connexion IRIS

Commencez par configurer votre connexion à l'aide des variables d'environnement dans un fichier .env:

IRIS_HOST=localhost
IRIS_PORT=9092
IRIS_NAMESPACE=USER
IRIS_USER=_SYSTEM
IRIS_PASSWORD=SYS

Connectez-vous à IRIS à l'aide du gestionnaire de contexte du module IRIStool:

from utils.iristool import IRIStool
import os
from dotenv import load_dotenv

load_dotenv()

with IRIStool( host=os.getenv('IRIS_HOST'), port=os.getenv('IRIS_PORT'), namespace=os.getenv('IRIS_NAMESPACE'), username=os.getenv('IRIS_USER'), password=os.getenv('IRIS_PASSWORD') ) as iris: # IRIStool manages the connection automatically pass

2. Création du schéma FHIR

Commencez par créer une table pour stocker les données FHIR, puis, tout en extrayant les données des paquets FHIR, créez des tables avec des capacités de recherche vectorielle pour chacune des ressources FHIR extraites (comme Patient, Osservability, etc.). 

Le module IRIStool simplifie la création de tables et d'index!

Table de référentiel FHIR

# Créer une table de référentiel principal pour les paquets FHIR brutsifnot iris.table_exists("FHIRrepository", "SQLUser"):
    iris.create_table(
        table_name="FHIRrepository",
        columns={
            "patient_id": "VARCHAR(200)",
            "fhir_bundle": "CLOB"
        }
    )
    iris.quick_create_index(
        table_name="FHIRrepository",
        column_name="patient_id"
    )

Table de patients avec support vectoriel

# Création d'une table de patients au moyen de la colonne vectorielle pour la recherche sémantiqueifnot iris.table_exists("Patient", "SQLUser"):
    iris.create_table(
        table_name="Patient",
        columns={
            "patient_row_id": "INT AUTO_INCREMENT PRIMARY KEY",
            "patient_id": "VARCHAR(200)",
            "description": "CLOB",
            "description_vector": "VECTOR(FLOAT, 384)",
            "full_name": "VARCHAR(200)",
            "gender": "VARCHAR(30)",
            "age": "INTEGER",
            "birthdate": "TIMESTAMP"
        }
    )
<span class="hljs-comment"># Création d'index standards</span>
iris.quick_create_index(table_name=<span class="hljs-string">"Patient"</span>, column_name=<span class="hljs-string">"patient_id"</span>)
iris.quick_create_index(table_name=<span class="hljs-string">"Patient"</span>, column_name=<span class="hljs-string">"age"</span>)

<span class="hljs-comment"># Création d'un index vectoriel HNSW pour la recherche par similarité</span>
iris.create_hnsw_index(
    index_name=<span class="hljs-string">"patient_vector_idx"</span>,
    table_name=<span class="hljs-string">"Patient"</span>,
    column_name=<span class="hljs-string">"description_vector"</span>,
    distance=<span class="hljs-string">"Cosine"</span>
)</code></pre>

3. Importation de données FHIR à l'aide de vecteurs

Générez facilement des intégrations vectorielles à partir des descriptions des patients FHIR et insérez-les dans IRIS:

from sentence_transformers import SentenceTransformer

# Initialisation du modèle de convertisseur model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')

# Exemple : Traitement des données du patient patient_description = "45-year-old male with hypertension and type 2 diabetes" patient_id = "patient-123"# Création d'un encodage vectoriel vector = model.encode(patient_description, normalize_embeddings=True).tolist()

# Insertion des données du patient à l'aide du vecteur iris.insert( table_name="Patient", patient_id=patient_id, description=patient_description, description_vector=str(vector), full_name="John Doe", gender="male", age=45, birthdate="1979-03-15" )

4. Recherche sémantique

Lorsque vos données sont téléchargées, vous pouvez effectuer des recherches par similarité:

# Requête de recherche
search_text = "patients with diabetes"
query_vector = model.encode(search_text, normalize_embeddings=True).tolist()

# définition de requête SQL query = f""" SELECT TOP 5 patient_id, full_name, description, VECTOR_COSINE(description_vector, TO_VECTOR(?)) as similarity FROM Patient ORDER BY similarity DESC """# définition des paramètres de requête parameters = [str(query_vector)]

# Recherche de patients similaires à l'aide de la recherche vectorielle results = iris.query(query, parameters)

# Impression des données du DataFrameifnot results.empty: print(f"{results['full_name']}: {results['similarity']:.3f}")

Conclusion

  • Le module IRIStool simplifie l'intégration d'IRIS avec des méthodes Python intuitives pour la création de tables et d'index
  • IRIS prend en charge le stockage hybride SQL + vecteur de manière native, ce qui permet de réaliser les deux requêtes traditionnelles et la recherche sémantique
  • Les intégrations vectorielles permettent une recherche intelligente dans les données de soins de santé FHIR à l'aide du langage naturel
  • Les index HNSW fournissent une recherche par similarité efficace à grande échelle

Cette approche prouve qu'InterSystems IRIS peut servir de base solide pour créer des applications de santé intelligentes avec des capacités de recherche sémantique sur les données FHIR.

0
0 8
Article Iryna Mykhailova · Nov 5, 2025 6m read

Salut!

C'est encore moi 😁. Dans l'article précédent Comment écrire un service API REST pour exporter le paquet FHIR généré au format JSON, nous avons généré une ressource DocumentReference, dont le contenu était encodé en Base64

Question!! Est-il possible d'écrire un service REST pour le décoder? Je voudrais vraiment savoir ce que contiennent les données du message🤔🤔🤔

Bien, allons-y!

1. Créez une nouvelle classe utilitaire datagen.utli.decodefhirjson.cls pour décoder les données contenues dans DocumentReference
 

Class datagen.utli.decodefhirjson Extends%RegisteredObject
{
}

2. Écrivez une fonction Python decodebase64docref pour 
a. parcourir le paquet FHIR
b. découvrir la ressource DocumentReference
  - récupérer le premier élément dans le contenu
   - récupérer la pièce jointe à partir de  contenu
     - récupérer les données à partir de la pièce jointe
c. décoder les données par Base64
 (pour cette partie, j'ai demandé l'aide de Chat-GPT😂🤫) 

Class datagen.utli.decodefhirjson Extends%RegisteredObject
{

ClassMethod decodebase64docref(fhirbundle = "") As%String [ Language = python ] { # w##class(datagen.utli.decodefhirjson).decodebase64docref() import base64 import json

def decode_discharge_summary(bundle_json):
    <span class="hljs-string">"""
    Extracts and decodes the Base64-encoded discharge summary note
    from a FHIR Bundle containing a DocumentReference.
    """</span>
    <span class="hljs-keyword">for</span> entry in bundle_json.get(<span class="hljs-string">"entry"</span>, []):
        resource = entry.get(<span class="hljs-string">"resource"</span>, {})
        <span class="hljs-keyword">if</span> resource.get(<span class="hljs-string">"resourceType"</span>) == <span class="hljs-string">"DocumentReference"</span>:
            # Traverse to the attachment
            content_list = resource.get(<span class="hljs-string">"content"</span>, [])
            <span class="hljs-keyword">if</span> not content_list:
                <span class="hljs-keyword">continue</span>
            attachment = content_list[<span class="hljs-number">0</span>].get(<span class="hljs-string">"attachment"</span>, {})
            base64_data = attachment.get(<span class="hljs-string">"data"</span>)
            <span class="hljs-keyword">if</span> base64_data:
                decoded_text = base64.b64decode(base64_data).decode(<span class="hljs-string">"utf-8"</span>)
                <span class="hljs-keyword">return</span> decoded_text
    <span class="hljs-keyword">return</span> None


# Example usage
# Load your FHIR Bundle JSON from a file or object
#with <span class="hljs-keyword">open</span>(<span class="hljs-string">"fhir_bundle.json"</span>, <span class="hljs-string">"r"</span>) <span class="hljs-keyword">as</span> f:
#    fhir_bundle = json.loads(f)
<span class="hljs-keyword">if</span> fhirbundle==<span class="hljs-string">""</span>:
    rtstr=f<span class="hljs-string">"&#x26a0;&#xfe0f; No input found - JSON string is required."</span>
    jsstr={<span class="hljs-string">"operation_outcome"</span> : rtstr}
    <span class="hljs-keyword">return</span> json.dumps(jsstr, indent=<span class="hljs-number">2</span>)

fhir_bundle = json.loads(fhirbundle)
decoded_note = decode_discharge_summary(fhir_bundle)

<span class="hljs-keyword">if</span> decoded_note:
    #<span class="hljs-keyword">print</span>(<span class="hljs-string">"&#x1f4dd; Decoded Discharge Summary:\n"</span>)
    #<span class="hljs-keyword">print</span>(decoded_note)
    rtstr=f<span class="hljs-string">"&#x1f4dd; Decoded Discharge Summary:\n {decoded_note}"</span>
<span class="hljs-keyword">else</span>:
    #<span class="hljs-keyword">print</span>(<span class="hljs-string">"&#x26a0;&#xfe0f; No DocumentReference with Base64 note found."</span>)
    rtstr=f<span class="hljs-string">"&#x26a0;&#xfe0f; No DocumentReference with Base64 note found."</span>
jsstr={<span class="hljs-string">"data"</span> : rtstr}
<span class="hljs-keyword">return</span> json.dumps(jsstr, indent=<span class="hljs-number">2</span>)

}

}

Pour tester cette fonction, j' essaie une astuce qui consiste à utiliser la fonction genfhirbundle pour générer un paquet FHIR dans une chaîne JSON,  comme expliqué dans l'article précédent Comment écrire un service API REST pour exporter le paquet FHIR généré au format JSON 

Générons un paquet FHIR et stockons-le dans une variable jsonstr

set jsonstr=##class(datagen.utli.genfhirjson).genfhirbundle(1)

Testons la fonction de décodage decodebase64docref  avec jsonstr

w##class(datagen.utli.decodefhirjson).decodebase64docref(jsonstr)

Bien 😉 Ça semble correct. Je peux désormais lire le message décodé.


Maintenant,  revenez à l'article précédent Comment écrire un service API REST pour exporter les données patient générées au format .csv

Nous aimerions ajouter une nouvelle fonction et mettre à jour le chemin d'accès pour la classe datagen.restservice .

1. Ajoutez une nouvelle fonction DecodeDocRef, qui est censée traiter le paquet FHIR  joint dans le corps au format JSON.

Par exemple, dans ce cas, nous prévoyons un POST.

Le contenu du corps est packagé par défaut sous la forme %CSP.BinaryStream et stocké dans la variable %request.Content, nous pouvons donc utiliser la fonction .Read()  à partir de la classe %CSP.BinaryStream pour lire le BinaryStream

ClassMethod DecodeDocRef() As%Status
{
    // récupération du corps - chaîne json#dim bistream As%CSP.BinaryStream =""set bistream=%request.Contentset jsstr=bistream.Read()
<span class="hljs-comment">//décodage des données de référence du document</span>
<span class="hljs-keyword">w</span> <span class="hljs-keyword">##class</span>(datagen.utli.decodefhirjson).decodebase64docref(jsstr)
<span class="hljs-keyword">return</span> <span class="hljs-built_in">$$$OK</span>

}

2. Ensuite, nous ajoutons un chemin d'accès pour le service REST et compilons😀

<Route Url="/decode/docref" Method="POST" Call="DecodeDocRef" />

La classe  datagen.restservice mise à jour se présentera comme suit.


Génial!! C'est tout ce qu'il y a à faire!😁

Nous allons vérifier cela dans Postman!!

COLLEZ le chemin d'accès  suivant

localhost/irishealth/csp/mpapp/decode/docref

avec le corps suivant (j'ai utilisé un paquet FHIR simplifié, vous pouvez tester le paquet complet😀)

{
    "resourceType": "Bundle",
    "type": "transaction",
    "id": "98bfce83-7eb1-4afe-bf2b-42916512244e",
    "meta": {
        "lastUpdated": "2025-10-13T05:49:07Z"
    },
    "entry": [
        {
            "fullUrl": "urn:uuid:5be1037d-a481-45ca-aea9-2034e27ebdcd",
            "resource": {
                "resourceType": "DocumentReference",
                "id": "5be1037d-a481-45ca-aea9-2034e27ebdcd",
                "status": "current",
                "type": {
                    "coding": [
                        {
                            "system": "http://loinc.org",
                            "code": "18842-5",
                            "display": "Discharge summary"
                        }
                    ]
                },
                "subject": {
                    "reference": "9e3a2636-4e87-4dee-b202-709d6f94ed18"
                },
                "author": [
                    {
                        "reference": "2aa54642-6743-4153-a171-7b8a8004ce5b"
                    }
                ],
                "context": {
                    "encounter": [
                        {
                            "reference": "98cd848b-251f-4d0b-bf36-e35c9fe68956"
                        }
                    ]
                },
                "content": [
                    {
                        "attachment": {
                            "contentType": "text/plain",
                            "language": "en",
                            "data": "RGlzY2hhcmdlIHN1bW1hcnkgZm9yIHBhdGllbnQgOWUzYTI2MzYtNGU4Ny00ZGVlLWIyMDItNzA5ZDZmOTRlZDE4LiBEaWFnbm9zaXM6IFN0YWJsZS4gRm9sbG93LXVwIGluIDIgd2Vla3Mu",
                            "title": "Discharge Summary Note"
                        }
                    }
                ]
            },
            "request": {
                "method": "POST",
                "url": "DocumentReference"
            }
        }
    ]
}

Ça marche parfaitement!!!😆😉

Merci infiniment à tous d'avoir pris le temps de lire cet article. 😘

0
0 10
Article Iryna Mykhailova · Nov 3, 2025 13m read

Bonjour à tous,

Continuons à travailler sur la génération de données de test et l'exportation des résultats via une API REST. 😁

Ici, je souhaite réutiliser la classe `datagen.restservice` créée dans l'article précédent : « Écriture d'un service API REST pour exporter les données patient générées au format .csv ».

Cette fois-ci, nous prévoyons de générer un bundle FHIR incluant plusieurs ressources pour tester le référentiel FHIR.

Voici une référence si vous souhaitez en savoir plus sur FHIR : « The Concept of FHIR: A Healthcare Data Standard Designed for the Future ».

C'est parti ! 😆

0
0 10
Article Iryna Mykhailova · Oct 23, 2025 6m read

Salut,

C'est moi encore 😁. Je travaille actuellement à la génération de fausses données patients à des fins de test avec Chat-GPT et Python. J'aimerais également partager mon apprentissage. 😑

Tout d'abord, créer un service d'API REST personnalisé est facile en utilisant %CSP.REST.

Commençons ! 😂

1. Créez une classe datagen.restservice qui étend %CSP.REST.

Class datagen.restservice Extends%CSP.REST
{
Parameter CONTENTTYPE = "application/json";
}

2. Ajoutez une fonction genpatientcsv() pour générer les données du patient et les regrouper dans une chaîne csv

0
0 18
Article Corentin Blondeau · Oct 13, 2025 4m read

Bonjour

Je vous soumets cet article en tant qu’état de l’art enrichi.
L’objectif est de réunir les différentes façons d’importer et d’exporter des CSV en un seul endroit.
Cet article est basé sur InterSystems 2024.1 .
N'hésitez pas à commenter pour rajouter des précisions.
Si vous voulez une deuxième partie sur l'export de CSV, faites le moi savoir.

Contexte

3
2 63
Article Guillaume Rongier · Sept 16, 2025 18m read

img

Dans cette section, nous allons découvrir comment utiliser Python comme langage principal dans IRIS, ce qui vous permettra d'écrire la logique de votre application en Python tout en profitant de la puissance d'IRIS.

Utilisation (irispython)

Tout d'abord, nous allons commencer par la méthode officielle, qui consiste à la mise en œuvre de l'interpréteur irispython.

Vous pouvez utiliser l'interpréteur irispython pour exécuter du code Python directement dans IRIS. Cela vous permet d'écrire du code Python et de l'exécuter dans le contexte de votre application IRIS.

Qu'est-ce qu'irispython?

irispython est un interpréteur Python qui se trouve dans le répertoire d'installation d'IRIS (<installation_directory>/bin/irispython) et qui sert à exécuter du code Python dans le contexte d'IRIS.

Cela vous permettra :

  • De configurer sys.path pour inclure les bibliothèques et les modules Python IRIS.
    • Cela est réalisé par le fichier site.py, qui se trouve dans <installation_directory>/lib/python/iris_site.py.
    • Pour plus d'informations, consultez l'article sur les modules Introduction aux modules Python.
  • Vous pourrez ainsi importer les modules iris, qui sont des modules spéciaux permettant d'accéder aux fonctionnalités IRIS, telles que la conversion de n'importe quelle classe ObjectScript vers Python, et réciproquement.
  • Vous pourrez corriger les problèmes d'autorisations et le chargement dynamique des bibliothèques du noyau iris.

Exemple d'utilisation d'irispython

Vous pouvez exécuter l'interpréteur irispython à partir de la ligne de commande:

<installation_directory>/bin/irispython

Prenons un exemple simple:

# src/python/article/irispython_example.py
import requests
import iris

def run():
    response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

    my_dict = response.json()

    for key, value in my_dict.items():
        print(f"{key}: {value}")  # print message: Hello World

    return my_dict

if __name__ == "__main__":
    print(f"Iris version: {iris.cls('%SYSTEM.Version').GetVersion()}")
    run()

Vous pouvez lancer ce script à l'aide de l'interpréteur irispython:

<installation_directory>/bin/irispython src/python/article/irispython_example.py

Vous verrez le résultat:

Iris version: IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2025.1 (Build 223U) Tue Mar 11 2025 18:23:31 EDT
message: Hello World

Il est présenté ici comment utiliser l'interpréteur irispython pour exécuter du code Python dans le contexte d'IRIS.

Avantages

  • Python d'abord : vous pouvez écrire la logique de votre application en Python, ce qui vous permet de profiter des fonctionnalités et des bibliothèques de Python.
  • Intégration IRIS : vous pouvez facilement intégrer votre code Python aux fonctionnalités et aux caractéristiques d'IRIS.

Inconvénients

  • Débogage limité : le débogage du code Python dans irispython n'est pas aussi simple que dans un environnement Python dédié.
    • Cela ne signifie pas que c'est impossible, mais ce n'est pas aussi facile que dans un environnement Python dédié.
    • Consultez la Section supoplémentaire for more details.
  • Environnement virtuel : il est difficile de configurer un environnement virtuel pour votre code Python dans irispython.
    • Cela ne signifie pas que c'est impossible, mais c'est difficile à réaliser à cause de l'environnement virtuel qui recherche par défaut un interpréteur appelé python ou python3, ce qui n'est pas le cas dans IRIS.
    • Consultez la Section supoplémentaire for more details.

Conclusion

En conclusion, en utilisant irispython, vous pouvez écrire la logique de votre application en Python tout en profitant de la puissance d'IRIS. Cependant, cet outil présente certaines limites en matière de débogage et de configuration de l'environnement virtuel.

Utilisation de WSGI

Dans cette section, nous allons découvrir comment utiliser WSGI (Interface de passerelle serveur Web) pour exécuter des applications Web Python dans IRIS.

WSGI est une interface standard entre les serveurs Web et les applications ou frameworks Web Python. Elle vous permet d'exécuter des applications Web Python dans un environnement de serveur Web.

IRIS prend en charge WSGI, ce qui signifie que vous pouvez exécuter des applications Web Python dans IRIS à l'aide du serveur WSGI intégré.

Utilisation

Pour utiliser WSGI dans IRIS, vous devez créer une application WSGI et l'enregistrer auprès du serveur web IRIS.

Pour plus de détails, consultez la documentation officielle.

Exemple d'utilisation de WSGI

Vous trouverez un template complet ici iris-flask-example.

Avantages

  • Frameworks Web Python : Pour créer vos applications Web, vous pouvez utiliser des frameworks Web Python populaires tels que Flask ou Django.
  • Intégration IRIS : Vous pouvez intégrer vos applications Web Python aux fonctionnalités IRIS en toute simplicité.

Inconvénients

  • Complexité : la configuration d'une application WSGI peut s'avérer plus complexe en comparaison avec une simple utilisation de uvicorn ou gunicorn avec un framework web Python.

Conclusion

En conclusion, l'utilisation de WSGI dans IRIS vous permet de créer des applications web puissantes à l'aide de Python tout en profitant des fonctionnalités et des capacités d'IRIS.

DB-API

Dans cette section, nous allons découvrir comment utiliser l'API Python DB pour interagir avec les bases de données IRIS.

L'API Python DB est une interface standard pour se connecter à des bases de données en Python. Elle vous permet d'exécuter des requêtes SQL et de récupérer les résultats dans la base de données.

Utilisation

Vous pouvez l'installer en utilisant pip:

pip install intersystems-irispython

Ensuite, vous pouvez utiliser l'API DB pour la connexion à une base de données IRIS et exécuter des requêtes SQL.

Exemple d'utilisation de DB-API

Vous l'utilisez comme n'importe quelle autre API Python DB. Voici un exemple:

# src/python/article/dbapi_example.py
import iris

def run():
    # Connexion à la base de données IRIS
# Ouverture d'une connexion au serveur
    args = {
        'hostname':'127.0.0.1', 
        'port': 1972,
        'namespace':'USER', 
        'username':'SuperUser', 
        'password':'SYS'
    }
    conn = iris.connect(**args)

    # Création d'un curseur
    cursor = conn.cursor()

    # Exécution d'une requête
    cursor.execute("SELECT 1")

    # Récupération de tous les résultats
    results = cursor.fetchall()

    for row in results:
        print(row)

    # Fermeture du curseur et de la connexion
    cursor.close()
    conn.close()
if __name__ == "__main__":
    run()

Ce script peut être exécuté à l'aide de n'importe quel interpréteur Python:

python3 /irisdev/app/src/python/article/dbapi_example.py

Vous verrez le résultat:

(1,)

Avantages

  • Interface standard : l'API DB fournit une interface standard pour se connecter aux bases de données, ce qui facilite le passage d'une base de données à l'autre.
  • Requêtes SQL : vous pouvez exécuter des requêtes SQL et récupérer les résultats de la base de données à l'aide de Python.
  • Accès à distance : vous pouvez vous connecter à des bases de données IRIS distantes à l'aide de l'API DB.

Inconvénients

  • Fonctionnalités limitées : l'API DB fournit uniquement un accès SQL à la base de données. Vous ne pourrez donc pas utiliser les fonctionnalités avancées d'IRIS telles que l'exécution de code ObjectScript ou Python.

Alternatives

Il existe également une édition communautaire de la DB-API, disponible ici : intersystems-irispython-community.

Elle offre une meilleure prise en charge de SQLAlchemy, Django, langchain et d'autres bibliothèques Python qui utilisent la DB-API.

Pour plus de détail, consultez la Section supplémentaire.

Conclusion

En conclusion, l'utilisation de l'API Python DB avec IRIS vous permet de créer des applications puissantes capables d'interagir de manière transparente avec votre base de données.

Notebook

Après avoir vu comment utiliser Python dans IRIS, nous allons découvrir comment utiliser Jupyter Notebooks avec IRIS.

Jupyter Notebooks est un excellent moyen d'écrire et d'exécuter du code Python de manière interactive. Il peut être utilisé avec IRIS pour profiter de ses fonctionnalités.

Utilisation

Pour utiliser Jupyter Notebooks avec IRIS, vous devez installer les packages notebook et ipykernel:

pip install notebook ipykernel

Ensuite, vous pouvez créer un nouveau Jupyter Notebook et sélectionner le noyau Python 3.

Exemple d'utilisation de Notebook

Vous pouvez créer un nouveau Jupyter Notebook et écrire le code suivant:

# src/python/article/my_notebook.ipynb
# Importation des modules nécessaires
import iris
# La magie
iris.system.Version.GetVersion()

Vous pouvez exécuter ce notebook à l'aide de Jupyter Notebook:

jupyter notebook src/python/article/my_notebook.ipynb

Avantages

  • Développement interactif : les notebooks Jupyter vous permettent d'écrire et d'exécuter du code Python de manière interactive, ce qui est idéal pour l'analyse et l'exploration de données.
  • Résulltat riche : vous pouvez afficher des résultats riches, tels que des graphiques et des tableaux, directement dans le notebook.
  • Documentation : vous pouvez ajouter de la documentation et des explications à côté de votre code, ce qui rend

Inconvénients

  • Configuration délicate : la configuration des notebooks Jupyter avec IRIS peut s'avérer délicate, en particulier au niveau de la configuration du noyau.

Conclusion

Pour conclure, l'utilisation des notebooks Jupyter avec IRIS vous permet d'écrire et d'exécuter du code Python de manière interactive tout en profitant des fonctionnalités d'IRIS. Cependant, la configuration peut s'avérer délicate, en particulier au niveau du noyau.

Section supplémentaire

À partir de cette section, nous aborderons certains sujets avancés liés à Python dans IRIS, tels que le débogage à distance du code Python ou encore l'utilisation d'environnements virtuels.

La plupart de ces sujets ne sont pas officiellement pris en charge par InterSystems, mais il est utile de les aborder si vous souhaitez utiliser Python dans IRIS.

Utilisation d'un interpréteur natif (sans irispython)

Dans cette section, nous allons voir comment utiliser un interpréteur Python natif au lieu de l'interpréteur irispython.

Cela vous permet d'utiliser des environnements virtuels prêts à l'emploi et d'utiliser l'interpréteur Python auquel vous êtes habitué.

Utilisation

Pour utiliser un interpréteur Python natif, vous devez installer IRIS localement sur votre machine et disposer du package iris-embedded-python-wrapper installé.

Vous pouvez l'installer avec pip:

pip install iris-embedded-python-wrapper

Ensuite, vous devez configurer certaines variables d'environnement pour faire référence à votre installation IRIS:

export IRISINSTALLDIR=<installation_directory>
export IRISUSERNAME=<username>
export IRISPASSWORD=<password>
export IRISNAMESPACE=<namespace>

Ensuite, vous pouvez exécuter votre code Python à l'aide de votre interpréteur Python natif:

python3 src/python/article/irispython_example.py
# src/python/article/irispython_example.py
import requests
import iris

def run():
    response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

    my_dict = response.json()

    for key, value in my_dict.items():
        print(f"{key}: {value}")  # message d'impression: Hello World

    return my_dict

if __name__ == "__main__":
    print(f"Iris version: {iris.cls('%SYSTEM.Version').GetVersion()}")
    run()

Pour plus de détails; consultez iris-embedded-python-wrapper documentation.

Avantages

  • Environnements virtuels : vous pouvez utiliser des environnements virtuels avec votre interpréteur Python natif, ce qui vous permet de gérer plus facilement les dépendances.
  • Workflow familier : vous pouvez utiliser votre interpréteur Python habituel, ce qui facilite l'intégration avec vos flux de travail existants.
  • Débogage : vous pouvez utiliser vos outils de débogage Python préférés, tels que pdb ou ipdb, pour déboguer votre code Python dans IRIS.

Inconvénients

  • Complexité de la configuration : la configuration des variables d'environnement et du package iris-embedded-python-wrapper peut s'avérer complexe, en particulier pour les débutants.
  • Non pris en charge officiellement : cette approche n'est pas prise en charge officiellement par InterSystems. Vous risquez donc de rencontrer des problèmes qui ne sont pas documentés ni pris en charge.

Edition communautaire de DB-API

Dans cette section, nous allons explorer l'édition communautaire de l'API DB, disponible sur GitHub.

Utilisation

Vous pouvez l'installer avec pip:

pip install sqlalchemy-iris

Cette option installe l'édition communautaire de DB-API.

Ou avec une version spécifique:

pip install https://github.com/intersystems-community/intersystems-irispython/releases/download/3.9.3/intersystems_iris-3.9.3-py3-none-any.whl

Ensuite, vous pouvez utiliser l'API DB pour vous connecter à une base de données IRIS et exécuter des requêtes SQL ou tout autre code Python qui utilise l'API DB, comme SQLAlchemy, Django, langchain, pandas, etc.

Exemple d'utilisation de DB-API

Vous pouvez l'utiliser comme n'importe quelle autre API Python DB. Exemple:

# src/python/article/dbapi_community_example.py
import intersystems_iris.dbapi._DBAPI as dbapi

config = {
    "hostname": "localhost",
    "port": 1972,
    "namespace": "USER",
    "username": "_SYSTEM",
    "password": "SYS",
}

with dbapi.connect(**config) as conn:
    with conn.cursor() as cursor:
        cursor.execute("select ? as one, 2 as two", 1)   # le deuxième argument est la valeur du paramètre
        for row in cursor:
            one, two = row
            print(f"one: {one}")
            print(f"two: {two}")

Vous pouvez exécuter ce script à l'aide de n'importe quel interpréteur Python:

python3 /irisdev/app/src/python/article/dbapi_community_example.py

Ou à l'aide de sqlalchemy:

from sqlalchemy import create_engine, text

COMMUNITY_DRIVER_URL = "iris://_SYSTEM:SYS@localhost:1972/USER"
OFFICIAL_DRIVER_URL = "iris+intersystems://_SYSTEM:SYS@localhost:1972/USER"
EMBEDDED_PYTHON_DRIVER_URL = "iris+emb:///USER"

def run(driver):
    # Création d'un moteur à l'aide du pilote officiel
    engine = create_engine(driver)

    with engine.connect() as connection:
        # Exécution d'une requête
        result = connection.execute(text("SELECT 1 AS one, 2 AS two"))

        for row in result:
            print(f"one: {row.one}, two: {row.two}")

if __name__ == "__main__":
    run(OFFICIAL_DRIVER_URL)
    run(COMMUNITY_DRIVER_URL)
    run(EMBEDDED_PYTHON_DRIVER_URL)

Vous pouvez exécuter ce script à l'aide de n'importe quel interpréteur Python:

python3 /irisdev/app/src/python/article/dbapi_sqlalchemy_example.py

Vous verrez le résultat:

one: 1, two: 2
one: 1, two: 2
one: 1, two: 2

Avantages

  • Meilleur prise en charge : il offre une meilleure prise en charge de SQLAlchemy, Django, langchain et d'autres bibliothèques Python qui utilisent l'API DB.
  • Développé par la communauté : il est maintenu par la communauté, ce qui signifie qu'il est susceptible d'être mis à jour et amélioré au fil du temps.
  • Compatibilité : il est compatible avec l'API DB officielle d'InterSystems, vous pouvez donc passer facilement de l'édition officielle à l'édition communautaire.

Inconvénients

  • Vitesse : la version communautaire n'est peut-être pas aussi optimisée que la version officielle, ce qui peut entraîner des performances plus lentes dans certains cas.

Débogage de code Python dans IRIS

Dans cette section, nous allons voir comment déboguer du code Python dans IRIS.

Par défaut, le débogage du code Python dans IRIS (dans objectscript avec la balise de langage ou %SYS.Python) n'est pas possible, mais la communauté a trouvé une solution pour vous permettre de déboguer le code Python dans IRIS.

Utilisation

Installez d'abord IoP Interopérabilité en Python:

pip install iris-pex-embedded-python
iop --init

Cela installera IoP et les nouvelles classes ObjectScript qui vous permettront de déboguer le code Python dans IRIS.

Ensuite, vous pouvez utiliser la classe IOP.Wrapper pour encapsuler votre code Python et activer le débogage.

Class Article.DebuggingExample Extends %RegisteredObject
{
ClassMethod Run() As %Status
{
    set myScript = ##class(IOP.Wrapper).Import("my_script", "/irisdev/app/src/python/article/", 55550) // Ajustez le chemin d'accès à votre module
    Do myScript.run()
    Quit $$$OK
}
}

Configurez ensuite VsCode pour utiliser le débogueur IoP en ajoutant la configuration suivante à votre fichier launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python in IRIS",
            "type": "python",
            "request": "attach",
            "port": 55550,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}/src/python/article",
                    "remoteRoot": "/irisdev/app/src/python/article"
                }
            ]
        }
    ]
}

Vous pouvez désormais exécuter votre code ObjectScript qui importe le module Python, puis connecter le débogueur dans VsCode au port 55550.

Vous pouvez exécuter ce script à l'aide de la commande suivante:

iris session iris -U IRISAPP '##class(Article.DebuggingExample).Run()'

Vous pouvez ensuite définir des points d'arrêt dans votre code Python, et le débogueur s'arrêtera à ces points d'arrêt, ce qui vous permettra d'inspecter les variables et de parcourir le code.

Vidéo de débogage à distance en action (pour IoP, mais le concept est le même):

Et vous disposez également de tracebacks dans votre code Python, ce qui est très utile pour le débogage.

Avec les tracebacks activés:

Traceback enabled

Avec les tracebacks désactivés:

Traceback disabled

Avantages

  • Débogage à distance : vous pouvez déboguer à distance le code Python exécuté dans IRIS, ce qui, à mon avis, change la donne.
  • Fonctionnalités de débogage Python : vous pouvez utiliser toutes les fonctionnalités de débogage Python, telles que les points d'arrêt, l'inspection des variables et l'exécution du code pas à pas.
  • Tracebacks : vous pouvez voir le traceback complet des erreurs dans votre code Python, ce qui est très utile pour le débogage.

Inconvénients

  • Complexité de la configuration : La configuration de l'IoP et du débogueur peut s'avérer complexe, en particulier pour les débutants.
  • Solution communautaire : Il s'agit d'une solution communautaire, qui peut donc être moins stable ou moins bien documentée que les solutions officielles.

Conclusion

En conclusion, le débogage de code Python dans IRIS est possible grâce à la solution communautaire IoP, qui vous permet d'utiliser le débogueur Python pour déboguer votre code Python exécuté dans IRIS. Cependant, cela nécessite une certaine configuration et peut ne pas être aussi stable que les solutions officielles.

IoP (Interopérabilité en Python)

Dans cette section, nous allons explorer la solution IoP (Interopérabilité en Python), qui vous permet d'exécuter du code Python dans IRIS dans une approche "Python d'abord".

Je développe cette solution depuis un certain temps déjà, c'est mon bébé, elle essaie de résoudre ou d'améliorer tous les points précédents que nous avons vus dans cette série d'articles.

Points clés de l'IoP:

  • Python d'abord : vous pouvez écrire la logique de votre application en Python, ce qui vous permet de profiter des fonctionnalités et des bibliothèques de Python.
  • Intégration IRIS : vous pouvez facilement intégrer votre code Python aux fonctionnalités et aux caractéristiques d'IRIS.
  • Débogage à distance : vous pouvez déboguer à distance votre code Python exécuté dans IRIS.
  • Tracebacks : vous pouvez voir le traceback complet des erreurs dans votre code Python, ce qui est très utile pour le débogage.
  • Environnements virtuels : vous bénéficiez d'une prise en charge des environnements virtuels, ce qui vous permet de gérer plus facilement les dépendances.

Pour en savoir plus sur IoP, vous pouvez consulter la documentation officielle.

Vous pouvez ensuite lire les articles suivants pour en savoir plus sur IoP:

🐍❤️ Comme vous pouvez le constater, IoP offre un moyen puissant d'intégrer Python à IRIS, ce qui facilite le développement et le débogage de vos applications.

Vous n'avez plus besoin d'utiliser irispython, vous n'avez plus à définir manuellement votre sys.path, vous pouvez utiliser des environnements virtuels et vous pouvez déboguer votre code Python exécuté dans IRIS.

Conclusion

J'espère que vous avez apprécié cette série d'articles sur Python dans IRIS.

N'hésitez pas à me contacter si vous avez des questions ou des commentaires à propos de cette série d'articles.

Bonne chance, amusez-vous avec Python dans IRIS!

0
0 25
Article Guillaume Rongier · Sept 11, 2025 6m read

img

Connaissant désormais bien Python et ses fonctionnalités, voyons comment nous pouvons tirer parti de Python dans IRIS.

Balise de langue

La balise de langue est une fonctionnalité d'IRIS qui vous permet d'écrire du code Python directement dans vos classes ObjectScript.

Cette fonctionnalité est utile pour le prototypage rapide ou lorsque vous souhaitez utiliser les fonctionnalités de Python sans créer de script Python séparé.

Utilisation

Pour utiliser la balise de langue, il faut définir une méthode de classe avec l'attribut Language = python. Exemple:

Class Article.LanguageTagExample Extends %RegisteredObject
{

ClassMethod Run() [ Language = python ]
{
        import requests

        response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

        my_dict = response.json()

        for key, value in my_dict.items():
            print(f"{key}: {value}") # print message: Hello World
}

}

Quels sont donc les avantages et les inconvénients de l'utilisation de la balise de langue?

Avantages

  • Simplicité : vous pouvez écrire du code Python directement dans vos classes ObjectScript sans avoir à créer de fichiers Python séparés.
  • Prototypage rapide : idéal pour le prototypage rapide ou le test de petits fragments de code Python.
  • Intégration : vous pouvez facilement intégrer du code Python à votre code ObjectScript.

Inconvénients

  • Code mixte : le mixage de code Python et ObjectScript peut rendre votre code plus difficile à lire et à maintenir.
  • Débogage : vous ne pouvez pas déboguer à distance le code Python écrit dans la balise de langage, ce qui peut constituer une limitation pour les applications complexes.
  • Tracebacks : les tracebacks Python ne s'affichent pas, vous ne voyez qu'un message d'erreur ObjectScript, ce qui peut rendre le débogage plus difficile.

Conclusion

La balise de langue est une fonctionnalité puissante qui vous permet d'écrire du code Python directement dans vos classes ObjectScript. Cependant, elle a ses limitations et il est important de l'utiliser de manière raisonnable. Pour les projets plus importants ou lorsque vous devez déboguer votre code Python, il est préférable de créer des scripts Python séparés et de les importer dans vos classes ObjectScript.

Importation de modules Python (modules pypi)

Maintenant que nous avons une bonne compréhension de la balise de langue, voyons comment importer des modules Python et les utiliser dans ObjectScript.

Tout d'abord, nous allons nous limiter aux modules intégrés et aux modules tiers provenant de PyPI, tels que module de demande requests, module numpy, etc.

Utilisation

Ici, nous allons faire la même chose, mais en utilisant uniquement le module de demande de PyPI.

Class Article.RequestsExample Extends %RegisteredObject
{

ClassMethod Run() As %Status
{
    set builtins = ##class(%SYS.Python).Import("builtins")
    Set requests = ##class(%SYS.Python).Import("requests")

    Set response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")
    Set myDict = response.json()

    for i=0:1:builtins.len(myDict)-1 {
        set key = builtins.list(myDict.keys())."__getitem__"(i)
        set value = builtins.list(myDict.values())."__getitem__"(i)
        write key, ": ", value, !
    }
}

}

Exécutons-le:

iris session iris -U IRISAPP '##class(Article.RequestsExample).Run()'

Vous verrez le résultat:

message: Hello World

Avantages

  • Accès aux bibliothèques Python : vous pouvez utiliser toutes les bibliothèques Python disponibles sur PyPI, ce qui vous donne accès à un vaste écosystème de bibliothèques et d'outils.
  • Un seul type de code : vous n'écrivez que du code ObjectScript, ce qui facilite la lecture et la maintenance.
  • Débogage : vous pouvez déboguer votre code ObjectScript comme s'il s'agissait uniquement de code ObjectScript, ce qui est le cas :)

Inconvénients

  • Bonne connaissance de Python : vous devez avoir une bonne compréhension de Python pour utiliser efficacement ses bibliothèques.
  • Consultez des exemples dans les articles sur les méthodes dunder.
  • Pas d'écriture de code Python : vous n'écrivez pas de code Python, mais du code ObjectScript qui appelle du code Python, ce qui évite le sucre syntaxique de Python.

Conclusion

En conclusion, l'importation de modules Python dans ObjectScript peut considérablement améliorer les capacités de votre application en tirant parti du vaste écosystème de bibliothèques Python. Cependant, il est essentiel de comprendre les compromis impliqués, tels que la nécessité d'une solide maîtrise de Python.

Importation de modules Python (modules personnalisés)

Continuons avec le même exemple, mais cette fois-ci, nous allons créer un module Python personnalisé et l'importer dans ObjectScript.

Cette fois-ci, nous utiliserons Python autant que possible, et ObjectScript ne sera utilisé que pour appeler le code Python.

Utilisation

Créons un module Python personnalisé dénommé my_script.py avec le contenu suivant:

import requests

def run():
    response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

    my_dict = response.json()

    for key, value in my_dict.items():
        print(f"{key}: {value}") # print message: Hello World

Maintenant, nous allons créer une classe ObjectScript pour importer et exécuter ce module Python:

Class Article.MyScriptExample Extends %RegisteredObject
{
    ClassMethod Run() As %Status
    {
        set sys = ##class(%SYS.Python).Import("sys")
        do sys.path.append("/irisdev/app/src/python/article")  // Adjust the path to your module

        Set myScript = ##class(%SYS.Python).Import("my_script")

        Do myScript.run()

        Quit $$$OK
    }
}

Maintenant, exécutons-le:

iris session iris -U IRISAPP '##class(Article.MyScriptExample).Run()'

⚠️ N'oubliez pas de modifier votre session iris afin de vous assurer que vous disposez de la dernière version du code. Pour plus d'informations, consultez le premier article. Vous verrez le résultat:

message: Hello World

Voici une démonstration de l'importation d'un module Python personnalisé dans ObjectScript et de l'exécution de son code.

Avantages

  • Modularité : vous pouvez organiser votre code Python en modules, ce qui facilite sa gestion et sa maintenance.
  • Syntaxe Python : vous pouvez écrire du code Python en utilisant sa syntaxe et ses fonctionnalités.
  • Débogage : cette fonctionnalité n'est pas disponible pour le moment, mais dans le prochain article, nous verrons comment déboguer du code Python dans IRIS.

Inconvénients

  • Gestion des chemins : vous devez gérer le chemin d'accès à votre module Python. Pour plus d'informations, consultez l'article [https://community.intersystems.com/post/introduction-python-modules] sur sys.path.
  • Connaissances Python : vous devez toujours avoir une bonne compréhension de Python pour écrire et maintenir vos modules.
  • Connaissances ObjectScript : vous devez savoir comment utiliser ObjectScript pour importer et appeler vos modules Python.

Conclusion

En conclusion, l'importation de modules Python dans ObjectScript peut considérablement améliorer les capacités de votre application en tirant parti du vaste écosystème de bibliothèques Python. Cependant, il est essentiel de comprendre les compromis impliqués, tels que la nécessité d'une solide maîtrise de Python.

0
0 21
Article Guillaume Rongier · Sept 10, 2025 5m read

img

Cet article vous présente le concept des environnements virtuels en Python, qui sont essentiels pour gérer les dépendances et isoler les projets du système d'exploitation.

Qu'est-ce qu'un environnement virtuel?

Un environnement virtuel est un dossier qui contient :

  • Une version spécifique de Python
  • Au démarrage, un répertoire site-packages vide

Les environnements virtuels vous aideront à isoler votre projet de l'installation Python du système d'exploitation et d'autres projets.

Utilisation

Pour utiliser les environnements virtuels, vous pouvez suivre les étapes suivantes:

  1. Création d'un environnement virtuel: Vous pouvez créer un environnement virtuel à l'aide du module venv fourni avec Python. Ouvrez votre terminal et exécutez:

    python -m venv .venv
    

    Remplacez .venv par le nom de l'environnement souhaité.

  2. Activation de l'environnement virtuel: Après avoir créé l'environnement virtuel, vous devez l'activer. La commande varie en fonction de votre système d'exploitation:

    • Sous Windows:
    .venv\Scripts\Activate.ps1
    

    Si vous rencontrez une erreur, vous devrez peut-être exécuter la commande suivante dans votre terminal

    Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force; .venv\Scripts\Activate.ps1
    
    • Sous macOS et Linux:
    source .venv/bin/activate
    

Une fois activé, le prompt de votre terminal se modifie pour indiquer que vous travaillez désormais dans l'environnement virtuel.

Exemple:

(.venv) user@machine:~/project$

Remarquez le préfixe (.venv) du prompt du terminal, qui indique que l'environnement virtuel est actif.

Vous pouvez maintenant installer des packages à l'aide de pip. Ils seront installés dans l'environnement virtuel plutôt que dans l'installation globale de Python.

Puis-je utiliser des environnements virtuels dans IRIS?

Bonne question!

La réponse est simple : oui et non.

  • Non, puisque IRIS ne prend pas officiellement en charge les environnements virtuels.
  • Oui, puisque après avoir lu tous ces articles, nous connaissons désormais le fonctionnement de Python, celui d'IRIS et nous savons ce qu'est un environnement virtuel. Nous sommes donc peut-être en mesure de simuler un environnement virtuel dans IRIS en utilisant les configurations et les paramètres appropriés.

Comment simuler un environnement virtuel dans IRIS?

Un environnement virtuel comprend deux éléments:

  • Une version spécifique de Python
  • Un répertoire site-packages

IRIS dispose d'un système appelé Flexible Python Runtime (environnement d'exécution Python flexible) qui nous donne la possibilité suivante:

  • utiliser une version spécifique de Python.
  • mettre à jour le sys.path pour inclure un répertoire spécifique.

Nous pouvons donc simuler un environnement virtuel dans IRIS en utilisant leFlexible Python Runtime et en configurant le sys.path pour inclure un répertoire spécifique et une version spécifique de Python. 🥳

La configuration d'un Flexible Python Runtime dans IRIS est facile, vous pouvez suivre les étapes décrites dans la documentation IRIS.

En bref, il faut:

  1. Configurez PythonRuntimeLibrary pour l'orienter vers le fichier lib python de la version Python spécifique que vous souhaitez utiliser.

    Exemple:

    • Windows : C:\Program Files\Python311\python3.dll (Python 3.11 sous Windows)
    • Linux : /usr/lib/x86_64-linux-gnu/libpython3.11.so.1.0 (Python 3.11 sous Ubuntu 22.04 avec architecture x86)
  2. Configurez le PythonPath pour l'orienter vers le répertoire site-packages de la version Python spécifique que vous souhaitez utiliser.

    Exemple:

    • Utilisez le répertoire site-packages de votre environnement virtuel, qui se trouve généralement dans le répertoire .venv/lib/python3.x/site-packages.

⚠️ Ainsi, toute votre instance IRIS sera configurée pour l'utilisation d'une version spécifique de Python et d'un répertoire site-packages spécifique.

🩼 Limitation :

  • Vous n'obtiendrez pas exactement le même sys.path que pour un environnement virtuel, car IRIS ajoutera automatiquement certains répertoires au sys.path, tels que <installation_directory>/lib/python et d'autres que nous avons examinés dans l'article sur les modules.

🤫 Si vous souhaitez automatiser cette opération, vous pouvez utiliser ce formidable package: iris-embedded-python-wrapper

Pour l'utiliser, il faut:

Que vous soyez dans votre environnement venv, puis installez le package:

(.venv) user@machine:~/project$
pip install iris-embedded-python-wrapper

Ensuite, liez simplement ce venv à IRIS à l'aide de la commande suivante:

(.venv) user@machine:~/project$
bind_iris

Vous verrez le message suivant:

INFO:iris_utils._find_libpyton:Created backup at /opt/intersystems/iris/iris.cpf.0f4a1bebbcd4b436a7e2c83cfa44f515
INFO:iris_utils._find_libpyton:Created merge file at /opt/intersystems/iris/iris.cpf.python_merge
IRIS Merge of /opt/intersystems/iris/iris.cpf.python_merge into /opt/intersystems/iris/iris.cpf
INFO:iris_utils._find_libpyton:PythonRuntimeLibrary path set to /usr/local/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/Python
INFO:iris_utils._find_libpyton:PythonPath set to /xxxx/.venv/lib/python3.11/site-packages
INFO:iris_utils._find_libpyton:PythonRuntimeLibraryVersion set to 3.11

Pour dissocier le venv d'IRIS, vous pouvez utiliser la commande suivante:

(.venv) user@machine:~/project$
unbind_iris

Conclusion

Vous avez découvert les avantages de l'utilisation d'environnements virtuels en Python, la manière de les créer et de les utiliser, ainsi que la manière de simuler un environnement virtuel dans IRIS à l'aide du Flexible Python Runtime.

0
1 30
Article Guillaume Rongier · Sept 9, 2025 3m read

img

Ce court article est consacré aux méthodes dunder de Python, également appelées méthodes magiques.

Qu'est-ce que les méthodes Dunder?

Les méthodes Dunder sont des méthodes spéciales en Python qui commencent et se terminent par deux traits de soulignement (__). Elles vous permettent de définir le comportement de vos objets pour les opérations intégrées, telles que l'addition, la soustraction, la représentation sous forme de chaîne, etc.

Parmi les méthodes dunder courantes, on peut citer:

  • __init__(self, ...): Appelé lorsqu'un objet est créé.
    • Comme notre méthode %OnNew dans ObjectScript.
  • __str__(self): Appelée par la fonction intégrée str() et print pour représenter l'objet sous forme de chaîne.
  • __repr__(self): Appelée par la fonction intégrée repr() pour représenter l'objet à des fins de débogage.
  • __add__(self, other): Appelée lorsque l'opérateur + est utilisé.
  • __len__(self): Appelée par la fonction intégrée len() pour renvoyer la longueur de l'objet.
  • __getitem__(self, key): Appelée pour récupérer un élément d'une collection à l'aide de la syntaxe d'indiçage.
  • __setitem__(self, key, value): Appelée pour définir un élément dans une collection à l'aide de la syntaxe d'indiçage.
  • ... et bien d'autres encore.

Pourquoi les méthodes Dunder sont-elles importantes et pertinentes dans le contexte IRIS?

Dans ObjectScript, nous n'avons pas de sucre syntaxique comme en Python, mais nous pouvons obtenir un comportement similaire à l'aide des méthodes dunder.

Exemple : nous avons importé un module Python qui contient une fonction renvoyant une liste Python, et nous souhaitons l'utiliser dans ObjectScript. Nous devons utiliser la méthode dunder __getitem__ pour accéder aux éléments de la liste.

# src/python/article/dunder_example.py
def get_list():
    return [1, 2, 3, 4, 5]
Class Article.DunderExample Extends %RegisteredObject
{

ClassMethod Run()
{
    Set sys = ##class(%SYS.Python).Import("sys")
    do sys.path.append("/irisdev/app/src/python/article")
    set dunderExample = ##class(%SYS.Python).Import("dunder_example")
    set myList = dunderExample."get_list"()
    for i=0:1:myList."__len__"()-1 {
        write myList."__getitem__"(i), !
    }
}

}

Lançons-la:

iris session iris -U IRISAPP '##class(Article.DunderExample).Run()'

Le résultat sera le suivant:

1
2
3
4
5

Cela montre comment utiliser les méthodes dunder pour interagir avec des objets Python dans un contexte IRIS, ce qui vous permet de tirer parti des capacités de Python tout en travaillant dans l'environnement ObjectScript.

Supplément

Une bonne utilisation de dunder consisterait à placer à la fin de votre script Python un bloc if __name__ == " __main__ ": afin d'empêcher l'exécution du code lorsque le script est importé en tant que module.

Rappelez-vous, le premier article expliquait que lorsque vous importiez un script, le code y était exécuté. Ce bloc vous permet de définir du code qui ne doit s'exécuter que lorsque le script est exécuté directement, et non lorsqu'il est importé.

Exemple:

# src/python/article/dunder_example.py
def get_list():
    return [1, 2, 3, 4, 5]

if __name__ == "__main__":
    print(get_list())

Conclusion

Ce que vous pouvez faire en Python, même avec son sucre syntaxique, vous pouvez le faire en ObjectScript avec les méthodes dunder.

0
0 30
Article Guillaume Rongier · Sept 4, 2025 6m read

img

Les modules, quel sujet ! Nous n'avons pas de notion équivalente en ObjectScript, mais c'est un concept fondamental en Python. Découvrons-le ensemble.

Qu'est-ce qu'un module?

Je considère les modules comme une couche intermédiaire entre les classes et les packages. Voici un exemple.

Un mauvais exemple :

# MyClass.py
class MyClass:
    def my_method(self):
        print("Hello from MyClass!")

Lorsque vous voulez utiliser cette classe dans un autre script, vous devez faire comme suit:

# class_usage.py
from MyClass import MyClass # weird, right?

my_instance = MyClass()
my_instance.my_method()

En quoi cet exemple est-il mauvais?

Tout d'abord, parce que les noms de fichiers doivent être écrits en snake_case conformément à la norme PEP 8, et qu'ils doivent donc être nommés my_class.py. Ensuite, parce que vous importez une classe à partir d'un fichier qui porte le même nom que la classe. Ce n'est pas une bonne pratique en Python.

Je sais que cela peut être déroutant, surtout si vous venez d'ObjectScript où les classes sont définies dans des fichiers portant le même nom que celui de la classe.

Notions avancées

Un module est un fichier Python

Donc, nous venons de voir que les modules peuvent être des fichiers Python, mais sans l'extension .py.

Mais attendez, cela signifie-t-il qu'un script python est également un module? Oui, tout à fait!

C'est pourquoi il faut être prudent lorsque vous importez un script, car celui-ci exécutera le code qui y est contenu. Consultez l'article Introduction à Python pour en savoir plus.

Un module est un dossier contenant un fichier __init__.py

Comment ça, un dossier peut être un module? Oui, c'est possible!

Un dossier peut être un module s'il contient un fichier __init__.py. Ce fichier peut être vide ou contenir le code d'initialisation du module.

Voici un exemple:

src/python/article/
└── my_folder_module/
    ├── __init__.py
    ├── my_sub_module.py
    └── another_sub_module.py
# my_folder_module/my_sub_module.py
class MySubModule:
    def my_method(self):
        print("Hello from MySubModule!")
# my_folder_module/another_sub_module.py
class AnotherSubModule:
    def another_method(self):
        print("Hello from AnotherSubModule!")
# my_folder_module/__init__.py
# Ce fichier peut être vide ou contenir le code d'initialisation du module.

Dans ce cas, my_folder_module est un module, et vous pouvez l'importer comme suit:

from my_folder_module import my_sub_module, another_sub_module

Ou si vous définissez un fichier __init__.py avec le contenu suivant:

# my_folder_module/__init__.py
from .my_sub_module import MySubModule
from .another_sub_module import AnotherSubModule

Vous pouvez l'importer de la manière suivante:

from my_folder_module import MySubModule, AnotherSubModule

Vous voyez la subtilité ? Vous pouvez importer les classes directement depuis le module sans spécifier le sous-module, car le fichier __init__.py est exécuté lorsque vous importez le module, et ce fichier peut définir les éléments disponibles dans l'espace de noms du module.

sys.path

Lorsque vous importez un module, Python le recherche dans les répertoires spécifiés dans le fichier sys.path. Il s'agit d'une liste de chaînes de caractères qui spécifie le chemin de recherche des modules.

Vous pouvez afficher le sys.path actuel en exécutant le code suivant:

import sys
print(sys.path)

Par défaut, le répertoire actuel ainsi que d'autres répertoires variés en fonction de votre installation Python sont inclus.

Vous pouvez également ajouter des répertoires à sys.path lors de l'exécution, ce qui est utile lorsque vous souhaitez importer des modules à partir d'un emplacement spécifique. Par exemple:

import sys
sys.path.append('/path/to/your/module')
from your_module import YourClass

Pour cette raison, dans l'article précédent, nous avons ajouté le chemin d'accès au module avant de l'importer:

Set sys = ##class(%SYS.Python).Import("sys")
do sys.path.append("/irisdev/app/src/python/article")
set my_module = ##class(%SYS.Python).Import("my_module")

sys.path et autres répertoires

Quels sont les autres répertoires dans sys.path? Il s'agit généralement des répertoires suivants:

  • Le répertoire contenant le script d'entrée (ou le répertoire actuel si aucun script n'est spécifié).
  • Les répertoires de la bibliothèque standard, qui contiennent les modules intégrés fournis avec Python.
  • Les répertoires site-packages contenant les packages tiers installés.

site-packages

Voici comment fonctionne site-packages. Lorsque vous installez un package à l'aide de pip, il est installé dans le répertoire site-packages, qui est automatiquement inclus dans sys.path. Cela vous permet d'importer le package sans avoir à spécifier son emplacement.

🤨🔍 Mais comment et où le répertoire site-packages est-il défini, et par qui?

Le répertoire site-packages est créé lors de l'installation de Python et se trouve généralement dans le répertoire lib de votre installation Python. Son emplacement exact dépend de votre système opérationnel et de la manière dont Python a été installé.

Par exemple, sur une installation Linux classique, le répertoire site-packages peut être accessible à l'emplacement suivant:

/usr/local/lib/python3.x/site-packages

Sous Windows, il peut se trouver à l'emplacement suivant:

C:\Python3x\Lib\site-packages

Lorsque vous installez un package à l'aide de pip, il est installé dans le répertoire site-packages, qui est automatiquement inclus dans sys.path. Cela vous permet d'importer le package sans avoir à spécifier son emplacement.

import site
print(site.getsitepackages())

🤨🔍 A quel moment et à quel endroit l'interpréteur Python lit-il le fichier site.py?

Le fichier site.py (qui se trouve dans le répertoire standard de la bibliothèque) est exécuté automatiquement au lancement de l'interpréteur Python. Il est responsable de la configuration du répertoire site-packages et de son ajout à sys.path. Ce fichier se trouve dans le répertoire standard de la bibliothèque de votre installation Python.

sys.path dans IRIS

Dans IRIS, nous avons également un fichier site.py, qui se trouve dans <installation_directory>/lib/python/iris_site.py. Ce fichier est exécuté lorsque vous démarrez ou importez un script/module dans IRIS, et il configure le sys.path pour vous.

En résumé, le fichier iris_site.py effectue les opérations suivantes:

  • il préserve le répertoire site-packages par défaut
  • il ajoute le répertoire <installation_directory>/lib/python/ à sys.path
    • c'est là que les modules Python IRIS sont situés, veuillez ne pas y placer vos modules
  • il ajoute le répertoire <installation_directory>/mgr/python/ à sys.path
    • c'est là que vous pouvez placer vos modules Python personnalisés
  • il ajoute la chaîne de configuration PythonPath à sys.path

Conclusion

Un module peut être:

  • un fichier Python (avec ou sans l'extension .py)
  • un dossier contenant un fichier __init__.py
  • un script Python (qui est également un module)
  • si vous ne réussissez pas à importer un module, vérifiez s'il se trouve dans la liste sys.path
0
0 21
Article Guillaume Rongier · Sept 3, 2025 3m read

img

Ce court article traite du PEP 8, le guide de style Python.

Qu'est-ce que le PEP 8?

En bref, le PEP 8 fournit des directives et des bonnes pratiques pour écrire du code Python.

  • les noms de variables doivent être en snake_case
  • les noms de classes doivent être en CamelCase
  • les noms de fonctions doivent être en snake_case
  • les constantes doivent être en UPPER_CASE
  • l'indentation doit être de 4 espaces (pas de tabulations)
  • les variables/fonctions privées doivent commencer par un trait de soulignement (_)
    • puisque les variables et fonctions privées n'existent pas en Python, il s'agit simplement d'une convention
  • votre script ne doit pas s'exécuter lorsqu'il est importé
    • rappelez-vous que lorsque vous importez un script, le code est exécuté, consultez le premier article
  • ...

Inutile de tout citer, mais gardez bien à l'esprit que cela vous aidera à comprendre le code de vos collègues et permettra à ces derniers de comprendre le vôtre ^^.

Vous avez peut-être déjà entendu parler du terme pythonic. Suivre les recommandations du PEP 8 est un moyen d'écrire du code Python considéré comme pythonique (ce n'est pas la seule méthode, mais cela en fait partie).

Pourquoi les instructions du PEP 8 sont-elles importantes et pertinentes pour les développeurs Python d'IRIS?

Dans IRIS, et en particulier dans ObjectScript, nous avons également un guide de style, qui repose principalement sur le camelCase pour les noms de variables et le PascalCase pour les noms de classes.

Malheureusement, PEP 8 recommande d'utiliser le snake_case pour les noms de variables et de fonctions.

Et comme vous le savez déjà, dans ObjectScript, le trait de soulignement (_) sert à la concaténation et ne nous convient évidemment pas.

Comment contourner ce problème ? Utilisez des guillemets doubles pour appeler les noms de variables/fonctions Python dans le code ObjectScript.

Exemple:

Class Article.PEP8Example Extends %RegisteredObject
{

ClassMethod Run()
{
    Set sys = ##class(%SYS.Python).Import("sys")
    do sys.path.append("/irisdev/app/src/python/article")
    set pep8Example = ##class(%SYS.Python).Import("pep8_example")
    do pep8Example."my_function"() // Observez les guillemets doubles autour du nom de la fonction
}

}

Cette commande appellera la fonction my_function dans le fichier pep8_example.py, qui est définie comme suit:

# src/python/article/pep8_example.py
def my_function():
    print("Hello, World!")

Lorsque vous exécutez la méthode Run de la classe Article.PEP8Example, le résultat suivant s'affiche:

iris session iris -U IRISAPP '##class(Article.PEP8Example).Run()'
Hello, World!

Ça y est!

0
0 37
Article Guillaume Rongier · Sept 2, 2025 6m read

img

Cet article présente une introduction à la programmation Python dans le contexte d'IRIS.

Avant toute chose, je vais aborder un sujet important : Fonctionnement de Python. Cela vous aidera à comprendre certains problèmes et certaines limites que vous pourriez rencontrer lorsque vous utilisez Python dans IRIS.

Tous les articles et exemples sont disponibles dans ce dépôt git: iris-python-article

Fonctionnement de Python

Langage interprété

Python est un langage interprété, ce qui signifie que le code est exécuté ligne par ligne lors de l'exécution, même lorsque vous importez un script.

Qu'est-ce que cela veut dire? Examinons le code suivant:

# introduction.py

def my_function():
    print("Hello, World!")

my_function()

Lorsque vous exécutez ce script, l'interpréteur Python lit le code ligne par ligne. Il définit d'abord la fonction my_function, puis appelle cette fonction, qui affiche "Hello, World!" à la console.

Exemple d'exécution directe du script:

python3 /irisdev/app/src/python/article/introduction.py 

Cela donnera le résultat suivant:

Hello, World!

Dans un contexte IRIS, que se passera-t-il si nous importons ce script ?

Class Article.Introduction Extends %RegisteredObject
{
    ClassMethod Run()
    {
        Set sys = ##class(%SYS.Python).Import("sys")
        do sys.path.append("/irisdev/app/src/python/article")

        do ##class(%SYS.Python).Import("introduction")
    }
}

Lançons-le:

iris session iris -U IRISAPP '##class(Article.Introduction).Run()'

Cela donnera le résultat suivant:

Hello, World!

En effet, l'interpréteur Python importe le code en l'interprétant, il définit d'abord la fonction, puis l'appelle, exactement comme si vous exécutiez le script directement mais vous ne l'exécutez pas, vous l'importez.

⚠️ Remarque importante : si vous importez le script sans appeler la fonction, rien ne se passera. La fonction est définie, mais elle ne s'exécutera pas jusqu'à ce que vous l'appeliez explicitement.

Compris? L'interpréteur Python exécute le code dans le fichier, et si vous n'appelez pas la fonction, elle ne s'exécutera pas.

Exemple d'importation sans appel:

# introduction1.py
def my_function():
    print("Hello, World!")

Lançons-le dans un interpréteur Python:

python3 /irisdev/app/src/python/article/introduction1.py 

Résultat:

# Aucun résultat, puisque la fonction est définie mais n'est pas appelée

Dans un contexte IRIS, si vous importez ce script:

Class Article.Introduction1 Extends %RegisteredObject
{
    ClassMethod Run()
    {
        Set sys = ##class(%SYS.Python).Import("sys")
        do sys.path.append("/irisdev/app/src/python/article")
        do ##class(%SYS.Python).Import("introduction1")
    }
}

Lançons-le:

iris session iris -U IRISAPP '##class(Article.Introduction1).Run()'

Vous ne verrez aucun résultat,puisque la fonction est définie mais n'est pas appelée.

🤯 Pourquoi cette nuance est-elle importante?

  • Lorsque vous importez un script Python, celui-ci exécute le code contenu dedans.
    • Vous ne souhaitez peut-être pas que cela se produise
  • Vous pouvez être dérouté en pensant que l'importation d'un script revient à l'exécuter, mais ce n'est pas le cas.

Mise en cache des importations

Lorsque vous importez un script Python, l'interpréteur Python met en cache le script importé. Cela signifie que si vous importez à nouveau le même script, il ne réexécutera pas le code de ce script, mais utilisera la version mise en cache.

Exemple:

Réutilisons le script introduction.py:

# introduction.py
def my_function():
    print("Hello, World!")

my_function()

Maintenant, faisons la même chose en réutilisant la classe Article.Introduction:

Class Article.Introduction Extends %RegisteredObject
{
    ClassMethod Run()
    {
        Set sys = ##class(%SYS.Python).Import("sys")
        do sys.path.append("/irisdev/app/src/python/article")
        do ##class(%SYS.Python).Import("introduction")
    }
}

Mais maintenant, nous allons l'exécuter deux fois de suite dans la même session IRIS:

iris session iris -U IRISAPP 

IRISAPP>do ##class(Article.Introduction).Run()
Hello, World!

IRISAPP>do ##class(Article.Introduction).Run()

IRISAPP>

🤯 Mais qu'est-ce que c'est que ça ?

Oui, Hello, World! n'est imprimé qu'une seule fois !

⚠️ Votre script importé est mis en cache. Cela signifie que si vous modifiez le script après l'avoir importé, les modifications ne seront pas prises en compte tant que vous n'aurez pas modifié la session IRIS.

Cela vaut également si vous utilisez la balise de langage python language tag dans IRIS:

Class Article.Introduction2 Extends %RegisteredObject
{

ClassMethod Run() [ Language = python ]
{
    import os

    if not hasattr(os, 'foo'):
        os.foo = "bar"
    else:
        print("os.foo already exists:", os.foo)
}

}

Lançons-le:

iris session iris -U IRISAPP

IRISAPP>do ##class(Article.Introduction2).Run()

IRISAPP>do ##class(Article.Introduction2).Run()
os.foo already exists: bar

Oh non, le module os est mis en cache et l'attribut foo n'est pas redéfini comme inexistant.

Conclusion

J'espère que cette introduction sera utile pour comprendre pourquoi, lorsque vous travaillez avec Python dans IRIS, vous pouvez rencontrer des comportements inattendus, notamment lors de l'importation de scripts et de la mise en cache.

À retenir lorsque vous travaillez avec Python dans IRIS:

  • Changez à chaque fois de session IRIS pour voir les modifications apportées à vos scripts Python.
    • Il ne s'agit pas d'un bug, c'est le fonctionnement normal de Python.
  • N'oubliez pas que l'importation d'un script exécute son code.

Bonus

Attendez! C'est illogique, si vous dites que lorsque vous importez un script, il est mis en cache. Pourquoi, lorsque je travaille avec la balise language tag = python, lorsque je modifie le script, cela fonctionne sans changer la session IRIS?

Bonne question, cela est dû au fait que la balise language tag est conçue pour que, chaque fois que vous l'exécutez, elle relise le script et l'exécute ligne par ligne comme s'il s'agissait de nouvelles lignes dans un interpréteur Python natif. La balise language tag n'importe pas le script, elle l'exécute simplement comme si vous l'exécutiez directement dans un interpréteur Python sans le relancer.

Exemple:

Class Article.Introduction2 Extends %RegisteredObject
{
ClassMethod Run() [ Language = python ]
{
    import os

    if not hasattr(os, 'foo'):
        os.foo = "bar"
    else:
        print("os.foo already exists:", os.foo)
}
}

Lançons-le:

iris session iris -U IRISAPP
IRISAPP>do ##class(Article.Introduction2).Run()

IRISAPP>do ##class(Article.Introduction2).Run()
os.foo already exists: bar  

Dans un interpréteur Python, cela se présentera comme suit:

import os

if not hasattr(os, 'foo'):
    os.foo = "bar"
else:
    print("os.foo already exists:", os.foo)

import os
if not hasattr(os, 'foo'):
    os.foo = "bar"
else:
    print("os.foo already exists:", os.foo)

Résultat:

os.foo already exists: bar # only printed once

Maintenant, c'est clair?

Suite:

  • Pep8
  • Modules
  • Méthodes Dunder
  • Utilisation de Python dans IRIS
  • ...
0
0 23
Article Liam Evans · Août 20, 2025 4m read

Dans le cadre de mon projet stagiaire, je développe une application backend Flask de l'API REST. Mon objectif est de l'héberger sur InterSystems IRIS à l'aide de l'interface WSGI. Il s'agit d'une approche relativement nouvelle qui n'est actuellement utilisée que dans quelques projets tels que AskMe. Pour aider ceux qui souhaitent se lancer, j'ai décidé d'écrire cet article afin de simplifier le processus.

Création d'une application Flask de base

Commençons par créer une application Flask minimale. Voici le code:

0
0 19
Article Lorenzo Scalese · Juil 28, 2025 17m read

Découvrez comment concevoir des agents IA évolutifs et autonomes qui combinent raisonnement, recherche vectorielle et intégration d'outils à l'aide de LangGraph.

cover

C'est trop long, vous n'avez pas lu

  • Les agents IA sont des systèmes proactifs qui combinent mémoire, contexte et initiative pour automatiser des tâches dépassant le simple champ d'action des chatbots.
  • LangGraph est un framework qui nous permet de créer des workflows d'IA complexes, en utilisant des nœuds (tâches) et des arêtes (connexions) avec une gestion d'état intégrée.
  • Ce guide vous explique comment créer un agent de support client basé sur l'IA qui classe les priorités, identifie les sujets pertinents et détermine si une escalade ou une réponse automatique est nécessaire.

Alors, les agents IA, c'est quoi exactement?

Soyons réalistes, le terme "agents IA" peut faire penser à des robots qui vont envahir votre bureau. En réalité, il s'agit de vos assistants proactifs qui peuvent rationaliser des flux de travail complexes et éliminer les tâches répétitives. Considérez-les comme la prochaine étape évolutive après les chatbots: ils ne se contentent pas d'attendre des instructions, ils lancent des actions, coordonnent plusieurs étapes et s'adaptent tout au long du processus.

Autrefois, créer un système "intelligent" signifiait jongler avec différents modèles pour la compréhension du langage, la génération de code, la recherche de données, etc., puis les assembler à la va-vite. Auparavant, vous passiez la moitié de votre temps dans l'enfer de l'intégration, et l'autre moitié à corriger les erreurs.

Les agents renversent la tendance. Ils regroupent le contexte, l'initiative et l'adaptabilité en un seul flux orchestré. Il ne s'agit pas seulement d'automatisation, mais d'intelligence au service d'une mission. Et grâce à des frameworks tels que LangGraph, la création de votre propre équipe d'agents peut même devenir... oserais-je dire, amusante?

image

LangGraph, c'est quoi exactement?

LangGraph est un cadre innovant qui révolutionne la manière dont nous construisons des applications complexes impliquant des modèles linguistiques à grande échelle (LLM).

Imaginez que vous dirigez un orchestre: chaque instrument (ou "nœud") doit savoir quand entrer, à quel volume jouer et dans quel ordre. LangGraph, dans ce cas**,** est votre baguette, qui vous donne les informations suivantes:

  • Structure graphique: utilise une structure graphique avec des nœuds et des arêtes, permettant aux développeurs de concevoir des flux de travail flexibles et non linéaires qui s'adaptent aux branches et aux boucles. Elle reflète les processus décisionnels complexes qui ressemblent au fonctionnement des voies neuronales.
  • Gestion d'état: LangGraph offre des outils intégrés pour la persistance d'état et la récupération d'erreurs, simplifiant la gestion des données contextuelles à différentes étapes d'une application. Il peut basculer efficacement entre la mémoire à court terme et la mémoire à long terme, améliorant ainsi la qualité des interactions grâce à des outils tels que Zep.
  • Intégration d'outils: Avec LangGraph, les agents LLM peuvent facilement collaborer avec des services ou des bases de données externes pour récupérer des données du monde réel, améliorant ainsi la fonctionnalité et la réactivité de vos applications.
  • Human-in-the-Loop: Au-delà de l'automatisation, LangGraph s'adapte aux interventions humaines dans les flux de travail, qui sont essentielles pour les processus décisionnels nécessitant une supervision analytique ou une réflexion éthique.

Lorsque vous créez un chatbot doté d'une mémoire réelle, un moteur d'histoires interactives ou une équipe d'agents chargés de résoudre un problème complexe, LangGraph transforme les tâches fastidieuses en une machine à états simple et visuelle.

Pour commencer

Pour commencer à utiliser LangGraph, vous aurez besoin d'une configuration de base qui implique généralement l'installation de bibliothèques essentielles telles que langgraph et langchain-openai. Ensuite, vous pourrez définir les nœuds (tâches) et les bords (connexions) au sein du graphe, en mettant efficacement en œuvre des points de contrôle pour la mémoire à court terme et en utilisant Zep pour les besoins en mémoire plus persistants.

Lorsque vous utilisez LangGraph, gardez à l'esprit les remarques suivantes:

  • Flexibilité de conception: Tirez parti de la puissante structure graphique pour prendre en compte les ramifications et les interactions potentielles du flux de travail qui ne sont pas strictement linéaires.
  • Interaction prudente avec les outils: Améliorez les capacités du LLM à l'aide d'outils externes, mais ne les remplacez pas. Fournissez à chaque outil des descriptions complètes pour permettre une utilisation précise.
  • Utilisation de solutions de mémoire riches: Utilisez la mémoire de manière efficace, soyez attentif à la fenêtre contextuelle du LLM et envisagez d'intégrer des solutions externes pour la gestion automatiquedu contenu factuel.

Nous avons abordé les bases de LangGraph, passons maintenant à un exemple pratique. Pour cela, nous allons développer un agent IA spécialement conçu pour le support client.

Cet agent recevra les demandes par e-mail, analysera la description du problème dans le corps du message, puis déterminera la priorité de la demande et le sujet/la catégorie/le secteur approprié.

Alors, attachez vos ceintures et c'est parti!

buckle up

Pour commencer, nous devons définir ce qu'est un "outil". Vous pouvez le considérer comme un "assistant manager" spécialisé pour votre agent, lui permettant d'interagir avec des fonctionnalités externes.

Le décorateur @tool est ici essentiel. LangChain simplifie la création d'outils personnalisés, ce qui signifie que vous définissez d'abord une fonction Python, puis appliquez le décorateur @tool.

tools

Illustrons cela en créant notre premier outil. Cet outil aidera l'agent à classer la priorité d'un ticket d'assistance informatique en fonction du contenu de l'e-mail:

    from langchain_core.tools import tool
    
    @tool
    def classify_priority(email_body: str) -> str:
        """Classify the priority of an IT support ticket based on email content."""
        prompt = ChatPromptTemplate.from_template(
            """Analyze this IT support email and classify its priority as High, Medium, or Low.
            
            High: System outages, security breaches, critical business functions down
            Medium: Non-critical issues affecting productivity, software problems
            Low: General questions, requests, minor issues
            
            Email: {email}
            
            Respond with only: High, Medium, or Low"""
        )
        chain = prompt | llm
        response = chain.invoke({"email": email_body})
        return response.content.strip()

Excellent! Nous avons maintenant une invite qui demande à l'IA de recevoir le corps de l'e-mail, de l'analyser et de classer sa priorité comme Élevée, Moyenne ou Faible.

C'est tout! Vous venez de créer un outil accessible à votre agent!

Créons maintenant un outil similaire pour identifier le sujet principal (ou la catégorie) de la demande de support:


    @tool
    def identify_topic(email_body: str) -> str:
        """Identify the main topic/category of the IT support request."""
        prompt = ChatPromptTemplate.from_template(
            """Analyze this IT support email and identify the main topic category.
            
            Categories: password_reset, vpn, software_request, hardware, email, network, printer, other
            
            Email: {email}
            
            Respond with only the category name (lowercase with underscores)."""
        )
        chain = prompt | llm
        response = chain.invoke({"email": email_body})
        return response.content.strip()

Nous devons maintenant créer un état, et dans LangGraph, cette petite partie est plutôt importante.

Considérez-le comme le système nerveux central de votre graphe. C'est ainsi que les nœuds communiquent entre eux, en se passant des petits mots comme des surdoués à l'école.

Selon la documentation:

“Un état est une structure de données partagée qui représente l'instantané actuel de votre application.”

Et en pratique? L'état est un message structuré qui circule entre les nœuds. Il transporte le résultat d'une étape comme entrée pour la suivante. En gros, c'est le ciment qui maintient l'ensemble de votre flux de travail.

Par conséquent, avant de construire le graphique, nous devons d'abord définir la structure de notre état. Dans cet exemple, notre état sera composé des éléments suivants:

  • La demande de l'utilisateur (corps de l'email)
  • La priorité attribuée
  • Le sujet identifié (catégorie)

C'est simple et clair, vous pouvez donc vous déplacer à travers le graphe comme un pro.

    from typing import TypedDict

    # Définition de la structure d'état
    class TicketState(TypedDict):
        email_body: str
        priority: str
        topic: str
        
    
    # Initialisation d'état
    initial_state = TicketState(
        email_body=email_body,
        priority="",
        topic=""
    )

Nœuds et bords: Composants clés de LangGraph

Les éléments fondamentaux de LangGraph sont les nœuds et les bords.

  • Nœuds: Il s'agit des unités opérationnelles du graphe qui effectuent le travail proprement dit. Un nœud se compose généralement d'un code Python capable d'exécuter n'importe quelle logique, qu'il s'agisse de calculs ou d'interactions avec des modèles linguistiques (LLM) ou des intégrations externes. Les nœuds sont essentiellement similaires aux fonctions ou agents individuels de la programmation traditionnelle.
  • Bords: les bords définissent le flux d'exécution entre les nœuds et déterminent ce qui se passe ensuite. Elles agissent comme des connecteurs qui permettent à l'état de passer d'un nœud à l'autre en fonction de conditions prédéfinies. Dans le contexte de LangGraph, les bords sont essentiels pour orchestrer la séquence et le flux de décision entre les nœuds.

Pour comprendre le fonctionnement des bords, prenons l'exemple simple d'une application de messagerie:

  • Nœuds sont similaires aux utilisateurs (ou à leurs appareils) qui participent activement à une conversation.
  • Bords symbolisent les fils de discussion ou les connexions entre les utilisateurs qui facilitent la communication.

Lorsqu'un utilisateur sélectionne un fil de discussion pour envoyer un message, un bord est créée, le reliant à un autre utilisateur. Chaque interaction, qu'il s'agisse d'envoyer un message textuel, vocal ou vidéo, suit une séquence prédéfinie, comparable au schéma structuré de l'état de LangGraph. Cela garantit l'uniformité et l'interprétabilité des données transmises le long des bords.

Contrairement à la nature dynamique des applications pilotées par les événements, LangGraph utilise un schéma statique qui reste cohérent tout au long de l'exécution. Il simplifie la communication entre les nœuds, permettant aux développeurs de s'appuyer sur un format stable, garantissant ainsi une communication fluide au niveau des bords.

Conception d'un flux de travail de base

L'ingénierie des flux dans LangGraph peut être conceptualisée comme la conception d'une machine d'état. Dans ce paradigme, chaque nœud représente un état ou une étape de traitement distinct, tandis que les arêtes définissent les transitions entre ces états. Cette approche est particulièrement avantageuse pour les développeurs qui cherchent à trouver un équilibre entre les séquences de tâches déterministes et les capacités décisionnelles dynamiques de l'IA. Commençons à construire notre flux en initialisant StateGraph avec la classe TicketState que nous avons définie précédemment.

    from langgraph.graph import StateGraph, START, END
    
    workflow = StateGraph(TicketState)

Ajout de nœuds: Les nœuds sont des éléments fondamentaux, définis pour exécuter des tâches spécifiques telles que la classification de la priorité d'un ticket ou l'identification de son sujet.

Chaque fonction de nœud reçoit l'état actuel, effectue son opération et renvoie un dictionnaire permettant de mettre à jour l'état:

   def classify_priority_node(state: TicketState) -> TicketState:
        """Node to classify ticket priority."""
        priority = classify_priority.invoke({"email_body": state["email_body"]})
        return {"priority": priority}

    def identify_topic_node(state: TicketState) -> TicketState:
        """Node to identify ticket topic."""
        topic = identify_topic.invoke({"email_body": state["email_body"]})
        return {"topic": topic}
        
        
    workflow.add_node("classify_priority", classify_priority_node)
    workflow.add_node("identify_topic", identify_topic_node)

Les méthodes classify_priority_node et identify_topic_node modifieront le TicketState et enverront la saisie du paramètre.

Création des bords: Définissez les bords pour connecter les nœuds:


    workflow.add_edge(START, "classify_priority")
    workflow.add_edge("classify_priority", "identify_topic")
    workflow.add_edge("identify_topic", END)

The classify_priority establishes the start, whereas the identify_topic determines the end of our workflow so far.

Compilation et exécution: Une fois les nœuds et les bords configurés, compilez le flux de travail et exécutez-le.


    graph = workflow.compile()
    result = graph.invoke(initial_state)

Très bien! Vous pouvez également générer une représentation visuelle de notre flux LangGraph.

graph.get_graph().draw_mermaid_png(output_file_path="graph.png")

Si vous exécutez le code jusqu'à ce point, vous obtiendrez un graphe similaire au suivant:

first_graph.png

Cette illustration visualise une exécution séquentielle: démarrage, suivi du classement des priorités, puis identification du sujet et enfin terminaison.

L'un des aspects les plus puissants de LangGraph est sa flexibilité, qui nous permet de créer des flux et des applications plus complexes. Par exemple, nous pouvons modifier le flux de travail pour ajouter des bords depuis START vers les deux nœuds avec la ligne suivante:

    workflow.add_edge(START, "classify_priority")
    workflow.add_edge(START, "identify_topic")

Cette modification aura pour conséquence que l'agent exécutera simultanément classify_priority et identify_topic.

Une autre fonctionnalité très utile de LangGraph est la possibilité d'utiliser des bords conditionnels. Ils permettent au flux de travail de se ramifier en fonction de l'évaluation de l'état actuel, ce qui permet un routage dynamique des tâches.

Améliorons notre flux de travail. Nous allons créer un nouvel outil qui analyse le contenu, la priorité et le sujet de la demande afin de déterminer s'il s'agit d'un problème hautement prioritaire nécessitant une escalade (c'est-à-dire l'ouverture d'un ticket pour être traité par une équipe humaine). Si ce n'est pas le cas, une réponse automatisée sera générée pour l'utilisateur.


    @tool
    def make_escalation_decision(email_body: str, priority: str, topic: str) -> str:
        """Decide whether to auto-respond or escalate to IT team."""
        prompt = ChatPromptTemplate.from_template(
            """Based on this IT support ticket, decide whether to:
            - "auto_respond": Send an automated response for simple/common or medium priority issues
            - "escalate": Escalate to the IT team for complex/urgent issues
            
            Email: {email}
            Priority: {priority}
            Topic: {topic}
            
            Consider: High priority items usually require escalation, while complex technical issues necessitate human review.
            
            Respond with only: auto_respond or escalate"""
        )
        chain = prompt | llm
        response = chain.invoke({
            "email": email_body,
            "priority": priority,
            "topic": topic
        })
        return response.content.strip()
        

De plus, si la demande est jugée de priorité faible ou moyenne (ce qui entraîne une décision "auto_respond"), nous effectuerons une recherche vectorielle pour récupérer les réponses historiques. Ces informations seront ensuite utilisées pour générer une réponse automatisée appropriée. Cependant, cela nécessitera deux outils supplémentaires:


    @tool
    def retrieve_examples(email_body: str) -> str:
        """Retrieve relevant examples from past responses based on email_body."""
        try:
            examples = iris.cls(__name__).Retrieve(email_body)
            return examples if examples else "No relevant examples found."
        except:
            return "No relevant examples found."

    @tool
    def generate_reply(email_body: str, topic: str, examples: str) -> str:
        """Generate a suggested reply based on the email, topic, and RAG examples."""
        prompt = ChatPromptTemplate.from_template(
            """Generate a professional IT support response based on:
            
            Original Email: {email}
            Topic Category: {topic}
            Example Response: {examples}
            
            Create a helpful, professional response that addresses the user's concern.
            Keep it concise and actionable."""
        )
        chain = prompt | llm
        response = chain.invoke({
            "email": email_body,
            "topic": topic,
            "examples": examples
        })
        return response.content.strip()

Maintenant, définissons les nœuds correspondants à ces nouveaux outils:

    
    def decision_node(state: TicketState) -> TicketState:
        """Node to decide on escalation or auto-response."""
        decision = make_escalation_decision.invoke({
            "email_body": state["email_body"],
            "priority": state["priority"],
            "topic": state["topic"]
        })
        return {"decision": decision}
        
    
    def rag_node(state: TicketState) -> TicketState:
        """Node to retrieve relevant examples using RAG."""
        examples = retrieve_examples.invoke({"email_body": state["email_body"]})
        return {"rag_examples": examples}

    def generate_reply_node(state: TicketState) -> TicketState:
        """Node to generate suggested reply."""
        reply = generate_reply.invoke({
            "email_body": state["email_body"],
            "topic": state["topic"],
            "examples": state["rag_examples"]
        })
        return {"suggested_reply": reply}
        
    
    def execute_action_node(state: TicketState) -> TicketState:
        """Node to execute final action based on decision."""
        if state["decision"] == "escalate":
            action = f"&#x1f6a8; ESCALATED TO IT TEAM\nPriority: {state['priority']}\nTopic: {state['topic']}\nTicket created in system."
            print(f"[SYSTEM] Escalating ticket to IT team - Priority: {state['priority']}, Topic: {state['topic']}")
        else:
            action = f"&#x2705; AUTO-RESPONSE SENT\nReply: {state['suggested_reply']}\nTicket logged for tracking."
            print(f"[SYSTEM] Auto-response sent to user - Topic: {state['topic']}")
        
        return {"final_action": action}
        
        
        
    workflow.add_node("make_decision", decision_node)
    workflow.add_node("rag", rag_node)
    workflow.add_node("generate_reply", generate_reply_node)
    workflow.add_node("execute_action", execute_action_node)

Le bord conditionnel utilisera alors le résultat du nœud make_decision pour diriger le flux:

    workflow.add_conditional_edges(
        "make_decision",
        lambda x: x.get("decision"),
        {
            "auto_respond": "rag",
            "escalate": "execute_action"
        }
    )

Si l'outil make_escalation_decision (via decision_node) renvoie "auto_respond", le workflow passe par le nœud rag (pour récupérer des exemples), puis par generate_reply (pour rédiger la réponse) et enfin par execute_action (pour enregistrer la réponse automatique).

En revanche, si la décision est “escalate”, le flux contournera le RAG et passera aux étapes de génération, passant directement à execute_action pour gérer l'escalade. Pour compléter le graphe en ajoutant les bords standard restants, procédez comme suit:

    workflow.add_edge("rag", "generate_reply")
    workflow.add_edge("generate_reply", "execute_action")
    workflow.add_edge("execute_action", END)

Remarque sur le jeu de données: pour ce projet, le jeu de données utilisé pour alimenter la génération augmentée par récupération (RAG) provient du jeu de données Customer Support Tickets dataset on Hugging Face. Le jeu de données a été filtré afin de n'inclure que les éléments classés dans la catégorie de support technique 'Technical Support' et limité aux saisies en anglais English. Cela a permis de garantir que le système RAG ne récupère que des exemples très pertinents et spécifiques au domaine pour les tâches de support technique.

À ce stade, notre graphique devrait ressembler au suivant:

graph.png

Lorsque vous exécutez ce graphe avec un e-mail qui entraîne une classification de priorité élevée et une décision "escalate", vous obtenez la réponse suivante:

image.png

Au même moment, une demande classée comme faible priorité et donnant lieu à une décision « auto_respond » déclenchera une réponse similaire à la suivante:

image.png

Alors... Est-ce que tout est rose?

Pas tout à fait. Il y a quelques obstacles à éviter:

  • Confidentialité des données: Soyez prudent avec les informations sensibles, ces agents nécessitent des mesures de protection.
  • Coûts informatiques: Certaines configurations avancées nécessitent des ressources importantes.
  • Hallucinations: Les LLM peuvent parfois inventer des choses (même s'ils restent plus intelligents que la plupart des stagiaires).
  • Non-déterminisme: Une même saisie peut donner des résultats différents, ce qui est excellent pour la créativité, mais problématique pour les processus rigoureux.

Cependant, la plupart de ces lacunes peuvent être comblées grâce à une bonne planification, aux bons outils et, bien sûr, à un peu de réflexion.

LangGraph transforme les agents IA, qui ne sont encore que des mots à la mode, en solutions fonctionnelles et tangibles. Que vous souhaitiez automatiser votre service client, traiter vos tickets informatiques ou créer des applications autonomes, ce framework rend tout cela possible et même agréable.

Avez-vous des questions ou des commentaires? Parlons-en. La révolution de l'IA a besoin de créateurs comme vous.

0
0 27
Article Sylvain Guilbaud · Juil 18, 2025 11m read

🛠️ Gestion des configurations d'InterSystems API Manager (IAM = Kong Gateway) en CI/CD

🔍 Contexte : configurations d'InterSystems IAM

Dans le cadre de l'intégration d'InterSystems IAM dans un environnement sécurisé et contrôlé, InterSystems IAM repose sur Kong Gateway pour gérer les API exposées. Kong agit comme une API Gateway moderne, capable de gérer l’authentification, la sécurité, la gestion du trafic, les plugins, et bien plus encore.

0
0 24
Article Sylvain Guilbaud · Juil 8, 2025 3m read

Si vous migrez d'Oracle vers InterSystems IRIS, comme beaucoup de mes clients, vous risquez de rencontrer des modèles SQL spécifiques à Oracle nécessitant une conversion.

Prenons l'exemple suivant:

SELECT (TO_DATE('2023-05-12','YYYY-MM-DD') - LEVEL + 1) AS gap_date
FROM dual
CONNECT BY LEVEL <= (TO_DATE('2023-05-12','YYYY-MM-DD') - TO_DATE('2023-05-02','YYYY-MM-DD') + 1);

Dans Oracle:

  • LEVEL est une pseudo-colonne utilisée dans les requêtes hiérarchiques (CONNECT BY). Elle commence à 1 et s'incrémente de 1.
  • CONNECT BY LEVEL <= (...) détermine le nombre de lignes à générer.
  • La différence entre les deux dates plus un donne 11, donc la requête génère 11 lignes, en comptant à rebours à partir du 12 mai 2023 jusqu'au 2 mai 2023.

Répartition du résultat:

LEVEL = 1  → 2023-05-12
LEVEL = 2  → 2023-05-11
...
LEVEL = 11 → 2023-05-02

La question est maintenant de savoir comment obtenir ce résultat dans InterSystems IRIS, qui ne prend pas en charge CONNECT BY?

Une solution consiste à implémenter une requête de type SQL à l'aide d'ObjectScript qui imite ce comportement. Vous trouverez ci-dessous un exemple de définition CREATE QUERY qui accepte une date de début STARTDATE et un nombre de jours DAYS, et renvoie la liste des dates par ordre descendant.


✅ InterSystems IRIS: mise en œuvre d'une requête de l'intervalle de date

CREATE QUERY GET_GAP_DATE(IN STARTDATE DATE, IN DAYS INT)
  RESULTS (GAP_DATE DATE)
  PROCEDURE
  LANGUAGE OBJECTSCRIPT

Execute(INOUT QHandle BINARY(255), IN STARTDATE DATE, IN DAYS INT) { SET QHandle("start") = STARTDATE SET QHandle("days") = DAYS SET QHandle("level") = 1 RETURN $$$OK }

Fetch(INOUT QHandle BINARY(255), INOUT Row %List, INOUT AtEnd INT) { IF (QHandle("level") > QHandle("days")) { SET Row = "" SET AtEnd = 1 } ELSE { SET Row = $ListBuild(QHandle("start") - QHandle("level") + 1) SET QHandle("level") = QHandle("level") + 1 } RETURN $$$OK }

Close(INOUT QHandle BINARY(255)) { KILL QHandle QUIT $$$OK }

Vous pouvez exécuter la commande CREATE QUERY Vous pouvez exécuter la commande CREATE QUERY ci-dessus dans le portail IRIS System Management, ou via un outil tel que DBeaver ou un éditeur Python/Jupyter Notebook utilisant JDBC/ODBC.


🧪 Exemple d'utilisation:

Pour générer le même résultat que la requête Oracle ci-dessus, utilisez:

SELECT * FROM GET_GAP_DATE(
  TO_DATE('2023-05-12', 'YYYY-MM-DD'),
  TO_DATE('2023-05-12', 'YYYY-MM-DD') - TO_DATE('2023-05-02', 'YYYY-MM-DD') + 1
);

Cela donnera le résultat suivant:

GAP_DATE
----------
2023-05-12
2023-05-11
...
2023-05-02
(11 rows)

🔁 Utilisation avancée: Jointure avec d'autres tables

Vous pouvez également utiliser cette requête comme sous-requête ou dans des jointures:

SELECT * 
FROM GET_GAP_DATE(TO_DATE('2023-05-12', 'YYYY-MM-DD'), 11) 
CROSS JOIN dual;

Cela vous permet d'intégrer des plages de dates dans des flux SQL plus importants.


J'espère que cela sera utile à tous ceux qui sont confrontés à des scénarios de migration d'Oracle vers IRIS ! Si vous avez mis au point des solutions alternatives ou si vous proposez des améliorations, n'hésitez pas à me faire part de vos commentaires.

0
0 31
Article Guillaume Rongier · Juil 2, 2025 4m read

Bonjour chers ingénieurs interface et développeurs d'applications,     

Saviez-vous que Python peut être utilisé dans des productions ou des intégrations?

L'interface utilisateur de configuration de production est low-code, mais dans de nombreux projets, vous pouvez arriver au point où il est nécessaire d'écrire du code. Comme nous l'avons vu dans le cours Architecture d'intégration, les Business Process comportent de nombreux emplacements où insérer du code, notamment l'éditeur BPL (pour les Business Process BPL) et l'éditeur DTL (pour les transformations de données).

😯 À partir d'InterSystems IRIS 2025.1, Python et InterSystems ObjectScript sont tous deux pris en charge dans les éditeurs BPL et DTL. 😄 Vous pouvez choisir entre ces langues selon vos préférences personnelles, et pas selon des besoins techniques. 😍

Rédaction du code Python dans l'éditeur BPL

Python est pris en charge dans l'éditeur BPL depuis InterSystems IRIS 2024.1. Examinons un Business Process BPL:

Business Process BPL comprend les activités suivantes (dans l'ordre) : activité Début, activité Affectation, activité Code avec un logo Python, activité If avec un logo Python, activité Transformation du côté vrai de l'activité If, et activité Fin.

Dans l'activité <code>, GetWinningBid, remarquez l'icône Python. En ouvrant cette activité <code>, on peut voir que le champ intitulé Code contient des instructions Python! Ces instructions utilisent la bibliothèque intégrée iris pour ouvrir un objet d'un ID donné.

Une activité Code provenant d'un éditeur BPL. Le langage est défini sur Python. Le code indique # Utilisation du corps de la requête pour ouvrir l'objet Bid avec l'ID donné. New line. bidID = request.id. New line. context.winningBid = iris.cls("AuctionServer.Bid")._OpenId(bidID).

Vous pouvez définir le langage pour l'ensemble du BPL (Python ou ObjectScript) via le paramètre Language dans l'onglet General u BPL, puis utiliser le menu déroulant Language Override (Remplacement du language) dans un champ de code donné pour remplacer la valeur par défaut du BPL.

L'activité <code> n'est pas la seule activité qui analyse le code dans un Business Process BPL. L'activité <code> analyse les instructions de code complètes, mais autres champs des activités BPL acceptent également des expressions de code. Vous pouvez les reconnaître grâce au menu déroulant Language Override (Remplacement du langage), où vous pouvez remplacer la valeur par défaut de BPL. 

Par exemple, l'activité <if>, qui crée un flux logique conditionnel, a un champ appelé Condition qui accepte des expressions de code. Il a un champ correspondant appelé Condition Language Override (Remplacement du langage de condition). Dans cet exemple, ce champ est défini sur Python.

Lorsque Python n'était pas encore pris en charge dans ces domaines, les ingénieurs d'interface devaient savoir comment écrire des expressions logiques dans ObjectScript. Par exemple, vous deviez savoir que || signifie Or, et && signifie And. Vous pouvez désormais utiliser Python, dont la syntaxe pour les expressions logiques est plus proche du langage naturel.

Dans l'éditeur BPL, s'il vous faut importer des paquetages Python, vous pouvez le faire sous les instructions Python From/Import dans l'onglet General.

Rédaction du code Python dans l'éditeur DTL 

Python est également pris en charge dans les champs de code de l'éditeur DTL depuis InterSystems IRIS 2025.1. Les utilisations courantes du code personnalisé dans DTL sont le formatage de chaînes et les calculs.

Une transformation de données DTL convertissant un objet source, AuctionServer.Bid, into a target object, AuctionServer.Order

Si vous devez importer des paquetages Python dans l'éditeur DTL, recherchez l'onglet Paramètres Transformation et utilisez le champ d' instruction Python From / Import. Le langage par défaut pour les expressions de code peut également être défini dans l'onglet d'instructions Transformation .

Dans l'onglet Paramètres de transformation du DTL, le langage est défini sur Python et le champ des instructions Python From / Import contient la mention from numpy import random.

Pour trouver les champs d'analyse de code des actions DTL, il suffit de rechercher tout champ associé à une liste déroulante Language Override. Par exemple, dans l'action <code> du DTL, vous pouvez écrire des instructions de code complètes. Les actions telles que Set, If, Trace et autres prennent en charge les expressions de code, qui peuvent être écrites en Python ou en ObjectScript.

Une activité de code issue d'une transformation de données DTL, avec le langage défini sur Python. Le contenu du champ de code indique bidders = [bid.User for bid in source.Lot.Bids()]. New line. bidders = set(bidders). New line. target.NumOutbid = (len(bidders) - 1).

Flux de travail axés sur le code

Si vous maîtrisez le processus d'édition de productions via un code, vous pouvez modifier les fichiers BPL et DTL via leurs fichiers de configuration. Cette méthode n'est pas aussi simple que les interfaces de l'éditeur, mais elle est très intuitive pour les programmeurs expérimentés.

Vous pouvez également utiliser Python pour écrire des méthodes dans des fonctions utilitaires personnalisées et des composants personnalisés, tels que des opérations commerciales et des services commerciaux (à l'exception des méthodes de rappel callback methods, comme défini dans la documentation).

Récapitulatif 

  • L'éditeur DTL et l'éditeur BPL prennent désormais en charge le code et les expressions Python. 
  • Si nécessaire, indiquez les paquetages que vous souhaitez importer via les paramètres généraux de BPL ou DTL. 
  • Vous pouvez définir un langage par défaut pour chaque DTL/BPL et remplacer des champs spécifiques si nécessaire.

Rejoignez la conversation!

  • Avez-vous déjà utilisé Python pour créer des intégrations personnalisées? 
  • Quelles questions avez-vous au sujet de la prise en charge de Python dans les intégrations?
  • Ajoutez vos commentaires ci-dessous!
0
0 28
Article Iryna Mykhailova · Juin 24, 2025 3m read

J'écris cet article principalement pour recueillir un consensus informel sur la façon dont les développeurs utilisent Python avec IRIS. N'hésitez donc pas à répondre au sondage à la fin de cet article ! Dans le corps de l'article, je détaillerai chaque choix proposé, ainsi que ses avantages, mais n'hésitez pas à le parcourir et à simplement répondre au sondage.

0
0 36
Article Sylvain Guilbaud · Mai 27, 2025 7m read

Je sais que ceux qui découvrent VS Code, Git, Docker, FHIR et d'autres outils peuvent parfois avoir des difficultés à configurer l'environnement. J'ai donc décidé de rédiger un article qui explique étape par étape l'ensemble du processus de configuration afin de faciliter les premiers pas.

Je vous serais très reconnaissant de bien vouloir laisser un commentaire à la fin de cet article pour me faire savoir si les instructions étaient claires, s'il manquait quelque chose ou si vous avez d'autres suggestions qui pourraient être utiles.

La configuration comprend:

✅ VS Code – Éditeur de code
✅ Git – Système de contrôle de version
✅ Docker – Lancement d'une instance de la communauté IRIS for Health
✅ Extension VS Code REST Client – Pour l'exécution de requêtes API FHIR
✅ Python – Pour l'écriture de scripts basés sur FHIR
✅ Jupyter Notebooks – Pour les tâches liées à l'IA et au FHIR

Avant de commencer: Vérifiez que vous disposiez des privilèges d'administrateur sur votre système.

Outre la lecture du guide, vous pouvez également suivre les étapes décrites dans les vidéos:

Pour Windows

<iframe allowfullscreen="" frameborder="0" height="360" src="https://www.youtube.com/embed/IyvuHbxCwCY" width="640"></iframe>

Pour macOS

<iframe allowfullscreen="" frameborder="0" height="360" src="https://www.youtube.com/embed/Ss7vU0l3JNU" width="640"></iframe>

Vous trouverez un sondage à la fin de l'article, merci de partager vos progrès. Vos commentaires sont très appréciés.

Alors, c'est parti!

1. Installation de Visual Studio Code (VS Code)

VS Code sera l'éditeur principal pour le développement.

Windows et amp; macOS

  1. Accédez à la page de téléchargement de VS Code: https://code.visualstudio.com/
  2. Téléchargez le programme d'installation pour votre système d'exploitation:
    • Windows: .exe file
    • macOS: .dmg file
  3. Exécutez le programme d'installation et suivez les instructions.
  4. (Windows uniquement) : pendant l'installation, cochez la case Add to PATH" (Ajouter au PATH).
  5. Vérifiez l'installation:
  • ouvrez un terminal (Command Prompt, , PowerShell ou Terminal macOS)
  • Exécutez:
code --version
  • Vous devriez voir le numéro de version.

2. Installation de Git

Git est nécessaire pour le contrôle de version, le clonage et la gestion des référentiels de code.

Windows

  1. Téléchargez la dernière version à partir de: https://git-scm.com/downloads
  2. Exécutez le programme d'installation:
    • Choisissez "Use Git from the Windows Command Prompt" (Utiliser Git à partir de l'invite de commande Windows).
    • Conservez les paramètres par défaut et terminez l'installation.
  3. Vérifiez l'installation:
git --version

macOS

  1. Ouvrez le terminal et exécutez:
git --version

Si Git n'est pas installé, macOS vous demandera d'installer les outils de ligne de commande Suivez les instructions.

3. Installation de Docker

Docker est indispensable pour exécuter InterSystems IRIS for Health Community.

Windows

1.    Téléchargez Docker Desktop à partir de: https://www.docker.com/products/docker-desktop
2.    Exécutez le programme d'installation et suivez les instructions.
3.    Redémarrez votre ordinateur après l'installation.
4.    Activez WSL 2 Backend (si cela vous est demandé).
5.    Verifiez l'installation

À remarquer: L'installation de Docker nécessite des privilèges d'administrateur sur votre machine et au moins un redémarrage.

macOS

1.    Téléchargez Docker Desktop pour Mac à partir de: https://www.docker.com/products/docker-desktop
2.    Installez-le en glissant Docker.app dans le dossier Applications.
3.    Ouvrez Docker à partir du menu Applications.

Pour vous assurer que le moteur Docker Desktop fonctionne sous Windows ou macOS, procédez comme suit:

Démarrez Docker Desktop

Windows: Ouvrez Docker Desktop à partir du menu Start. L'icône Docker en forme de baleine devrait apparaître dans votre barre d'état système.

Mac: Lancez Docker Desktop à partir du dossier Applications. Une fois l'application lancée, l'icône Docker en forme de baleine apparaîtra dans la barre de menu.

Attendez l'initialisation

Une fois que vous avez lancé Docker Desktop, le moteur peut prendre un certain temps à démarrer. Recherchez un message d'état indiquant que Docker est "running" (en cours d'exécution) ou "started" (démarré).

Vérifiez via le terminal/Command Prompt:

Ouvrez le terminal (ou Command Prompt/PowerShell pour Windows) et exécutez:

docker --version

ou

docker info

Dépannage

Si le moteur ne fonctionne pas, essayez de redémarrer Docker Desktop ou vérifiez s'il y a des messages d'erreur dans l'interface utilisateur de Docker Desktop. Assurez-vous également que votre système répond aux exigences de Docker Desktop. Vous pouvez voir des messages d'erreur confus faisant référence à des pipes si vous essayez de créer une image Docker sans que Docker Desktop soit en cours d'exécution.

4. Création de l'image IRIS for Health et son exécution à l'aide de Docker

Avant de pouvoir démarrer un conteneur Docker exécutant IRIS for Health Community (qui comprend notre serveur FHIR), nous devons le créer.

  1. Clonez le référentiel FHIR dans un répertoire approprié de votre système de fichiers. Ouvrez un terminal dans VS Code et clonez ce référentiel à l'aide de la commande suivante:
    git clone https://github.com/pjamiesointersystems/Dockerfhir.git
     
  2. Accédez à ce répertoire et ouvrez le dossier dans VS Code. Suivez les instructions du fichier readme pour créer et exécuter le conteneur. Une étape essentielle consiste à vous assurer que le référentiel de base est disponible dans votre magasin Docker. Vous pouvez le faire à l'aide de la commande dans le terminal VS Code:
    docker pull containers.intersystems.com/intersystems/irishealth-community:latest-em
    Vous devriez recevoir une confirmation après quelques minutes.
  3. Accédez au répertoire dans VS Code où se trouve le fichier docker-compose.yaml, puis exécutez la commande suivante:
    docker-compose build 
    Cela lancera le processus de compilation, qui peut prendre jusqu'à 10 minutes, au cours desquelles un référentiel FHIR complet sera créé et chargé avec un échantillon de patients. 
  4. Une fois le processus de compilation terminé, lancez le conteneur à l'aide de la commande suivante:
    docker-compose up -d
    suivi par
    docker ps
    Vous devriez voir un conteneur nommé **iris-fhir** en cours d'exécution. Si le conteneur ne démarre pas, vérifiez les journaux:
    docker logs iris-fhir
     

5. Installation de l'extension VS Code REST Client

Cette extension vous permet d'envoyer des requêtes API FHIR depuis VS Code.

  1. Ouvrez VS Code.
  2. Accédez aux extensions (Ctrl + Shift + X or Cmd + Shift + X on macOS).
  3. Recherchez "REST Client". Il existe plusieurs clients REST, veuillez installer celui-ci:
  4. Clickez le bouton "Install".

6. Installation de Python

Python est indispensable pour les tâches de programmation liées à FHIR.

Windows

1.    Télécharger Python à partir de: https://www.python.org/downloads/
2.    Exécutez le programme d'installation et cochez la case "Add to PATH" (Ajouter au chemin). Vous aurez besoin d'informations d'identification administratives pour apporter des modifications au chemin d'accès
3.    Terminez l'installation.
4.    Verifiez l'installation:

python --version

macOS

  1. Ouvrez le Terminal et installez Python via Homebrew:
    Brew install python
    Si vous n'avez pas d'Homebrew, installez-le d'abord:
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
     
  2. Verifiez l'installation:
python3 --version

7. Installation des blocs-notes Jupyter

Les notebooks Jupyter sont utilisés pour l'IA et le FHIR, ainsi que pour les tâches  FHIR SQL.

Windows & macOS

  1. Ouvrez le terminal (Command Prompt, PowerShell, ou macOS Terminal).
  2. Installez Jupyter à l'aide de pip:
    pip install jupyter
    jupyter --version
     
  3. Exécutez le bloc-note Jupyter:
jupyter notebook

Jupyter s'ouvrira alors dans votre navigateur web.

8.  Validation

Exécutez votre conteneur en accédant à votre fichier Docker Compose dans le shell. Exécutez la commande 

docker compose up -d
docker ps

Accédez au Portail de gestion d'IRIS:

  • Ouvrez votre navigateur et accédez à: http://localhost:8080/csp/sys/UtilHome.csp
  • Informations d'identification par défaut:

Nom d'utilisateur: _SYSTEM
Mot de passe: ISCDEMO

Accédez à l'API FHIR

  • Ouvrez votre navigateur et accédez à: http://localhost:8080/csp/healthshare/demo/fhir/r4/metadata

Dernières vérifications

Exécutez les commandes suivantes pour vérifier toutes les installations:

code --version       # VS Code
git --version        # Git
docker --version     # Docker
python --version     # Python
jupyter --version    # Jupyter

Si tout fonctionne, vous avez installé correctement tous les logiciels ci-dessus.

Dépannage

ProblèmeSolution
"Command not found" (Commande introuvable) pour n'importe quel outilVérifiez qu'il a bien été ajouté au PATH (chemin) (réinstallez-le si nécessaire).
Docker ne fonctionne pas sous WindowsRedémarrez Docker Desktop et vérifiez que WSL 2 backend est activé.
Le conteneur IRIS ne démarre pasExécutez docker logs iris-fhir pour vérifier les erreurs.
Impossible d'accéder à l'API FHIR Vérifiez que le conteneur est en cours d'exécution (docker ps).

Merci de votre aide. J'attends vos commentaires avec impatience!

0
0 30
Article Lorenzo Scalese · Avr 30, 2025 5m read

Après tant d'années d'attente, nous avons enfin un pilote officiel disponible sur Pypi

De plus, j'ai découvert que le pilote JDBC était enfin disponible sur Maven depuis déjà 3 mois,  et le pilote .Net driver - surNuget depuis plus d'un mois.

 La mise en œuvre de la DB-API et que les fonctions devraient au moins être définies par cette norme. La seule différence devrait se situer au niveau de SQL.

Et ce qui est intéressant dans l'utilisation de bibliothèques existantes, c'est qu'elles ont déjà mis en œuvre d'autres bases de données en utilisant le standard DB-API, et que ces bibliothèques s'attendent déjà à ce que le pilote fonctionne.

J'ai décidé de tester le pilote officiel d'InterSystems en mettant en œuvre son support dans la bibliothèque SQLAlchemy-iris.

executemany

Préparez une opération de base de données (requête ou commande) et exécutez-la en fonction de toutes les séquences de paramètres ou de mappages trouvées dans la séquence seq_of_parameters.

Cette fonction très utile permet d'insérer plusieurs lignes à la fois. Commençons par un exemple simple

import iris

host = "localhost" port = 1972 namespace = "USER" username = "_SYSTEM" password = "SYS" conn = iris.connect( host, port, namespace, username, password, )

with conn.cursor() as cursor: cursor = conn.cursor()

res = cursor.execute(<span class="hljs-string">"DROP TABLE IF EXISTS test"</span>)
res = cursor.execute(
    <span class="hljs-string">"""
CREATE TABLE test (
        id IDENTITY NOT NULL,
        value VARCHAR(50)
) WITH %CLASSPARAMETER ALLOWIDENTITYINSERT = 1
"""</span>
)

cursor = conn.cursor()
res = cursor.executemany(
    <span class="hljs-string">"INSERT INTO test (id, value) VALUES (?, ?)"</span>, [
        (<span class="hljs-number">1</span>, <span class="hljs-string">'val1'</span>),
        (<span class="hljs-number">2</span>, <span class="hljs-string">'val2'</span>),
        (<span class="hljs-number">3</span>, <span class="hljs-string">'val3'</span>),
        (<span class="hljs-number">4</span>, <span class="hljs-string">'val4'</span>),
    ]
)</code></pre>

Cela fonctionne bien, mais que se passe-t-il s'il faut insérer une seule valeur par ligne.

    res = cursor.executemany(
        "INSERT INTO test (value) VALUES (?)", [
            ('val1', ),
            ('val2', ),
            ('val3', ),
            ('val4', ),
        ]
    )

Cela conduit malheureusement à une exception inattendue

RuntimeError: Cannot use list/tuple for single values (Impossible d'utiliser une liste/tuple pour des valeurs uniques)

Pour certaines raisons, une seule valeur par ligne est autorisée, et InterSystems demande d'utiliser une méthode différente

    res = cursor.executemany(
        "INSERT INTO test (value) VALUES (?)", [
            'val1',
            'val2',
            'val3',
            'val4',
        ]
    )

De cette façon, cela fonctionne bien

fetchone

Récupère la ligne suivante d'un ensemble de résultats de requête, en renvoyant une seule séquence, ou None lorsqu'il n'y a plus de données disponibles.

Un exemple simple sur sqlite

import sqlite3
con = sqlite3.connect(":memory:")

cur = con.cursor() cur.execute("SELECT 1 one, 2 two") onerow = cur.fetchone() print('onerow', type(onerow), onerow) cur.execute("SELECT 1 one, 2 two union all select '01' as one, '02' as two") allrows = cur.fetchall() print('allrows', type(allrows), allrows)

fournit

onerow <class 'tuple'> (1, 2)
allrows <class 'list'> [(1, 2), ('01', '02')]

Et avec le pilote InterSystems

import iris

con = iris.connect( hostname="localhost", port=1972, namespace="USER", username="_SYSTEM", password="SYS", )

cur = con.cursor() cur.execute("SELECT 1 one, 2 two") onerow = cur.fetchone() print("onerow", type(onerow), onerow) cur.execute("SELECT 1 one, 2 two union all select '01' as one, '02' as two") allrows = cur.fetchall() print("allrows", type(allrows), allrows)

par certaines raisons fournit

onerow <class 'iris.dbapi.DataRow'> <iris.dbapi.DataRow object at 0x104ca4e10>
allrows <class 'tuple'> ((1, 2), ('01', '02'))

Qu'est-ce que DataRow, et pourquoi ne pas utiliser un tuple ou au moins une liste

Exceptions

SLa norme décrit une variété de classes d'exceptions que le pilote est censé utiliser, au cas où quelque chose ne fonctionnerait pas. Or, le pilote InterSystems ne les utilise pas du tout, se contentant de déclencher une erreur RunTime pour toute raison, ce qui, de toute façon, est contraire à la norme.

L'application peut s'appuyer sur le type d'exception qui se produit et se comporter en conséquence. Mais le pilote InterSystems ne fournit aucune différence. Par ailleurs, SQLCODE serait utile, mais il doit être extrait du message d'erreur

Conclusion

Au cours des tests, j'ai donc trouvé plusieurs bogues

  • Erreurs aléatoires survenant à tout moment <LIST ERROR> Format de liste incorrect, type non supporté pour IRISList; Détails : type détecté : 32
    • fonctionnent correctement, si vous réessayez juste après l'erreur
  • Des erreurs de segmentation ont été détectées, je ne sais même pas comment cela se produit
  • Résultat inattendu de la fonction fetchone
  • Fonctionnement inattendu de la fonction executemany, pour une seule ligne de valeur
  • Les exceptions ne sont pas du tout implémentées, des exceptions différentes devraient être générées en cas d'erreurs différentes, et les applications s'appuient sur ces exceptions
  • Python intégré peut être interrompu en cas d'installation à côté d'IRIS
    • en raison du même nom utilisé par Python intégré et ce pilote, il remplace ce qui est déjà installé avec IRIS et peut l'interrompre

SQLAlchemy-iris supporte maintenant le pilote officiel d'InterSystems, mais ceci en raison d'une incompatibilité avec Python intégré et de plusieurs bogues découverts lors des tests. Installation à l'aide de cette commande, avec l'option définie

pip install sqlalchemy-iris[intersystems]

Et pour une utilisation simple, l'URL devrait être iris+intersystems://

from sqlalchemy import Column, MetaData, Table
from sqlalchemy.sql.sqltypes import Integer, VARCHAR
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase

DATABASE_URL = "iris+intersystems://_SYSTEM:SYS@localhost:1972/USER" engine = create_engine(DATABASE_URL, echo=True)

# Create a table metadata metadata = MetaData()

classBase(DeclarativeBase):passdefmain(): demo_table = Table( "demo_table", metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("value", VARCHAR(50)), )

demo_table.drop(engine, checkfirst=<span class="hljs-keyword">True</span>)
demo_table.create(engine, checkfirst=<span class="hljs-keyword">True</span>)
<span class="hljs-keyword">with</span> engine.connect() <span class="hljs-keyword">as</span> conn:
    conn.execute(
        demo_table.insert(),
        [
            {<span class="hljs-string">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-string">"value"</span>: <span class="hljs-string">"Test"</span>},
            {<span class="hljs-string">"id"</span>: <span class="hljs-number">2</span>, <span class="hljs-string">"value"</span>: <span class="hljs-string">"More"</span>},
        ],
    )
    conn.commit()
    result = conn.execute(demo_table.select()).fetchall()
    print(<span class="hljs-string">"result"</span>, result)

main()

En raison de bogues dans le pilote InterSystems, certaines fonctionnalités peuvent ne pas fonctionner comme prévu. J'espère que cela sera corrigé à l'avenir

0
0 27
InterSystems officiel Adeline Icard · Avr 8, 2025

Résumé des alertes

Alert ID Produit et versions concernés Exigences explicites
DP-439207 Plateforme de données InterSystems IRIS® 2024.3 (AIX) Installations AIX utilisant le traitement JSON et les caractères Unicode non-Latin-1
DP-439280 InterSystems IRIS 2024.3 (conteneurs avec IntegratedML) Conteneurs IntegratedML utilisant TensorFlow

Détail des alertes

DP-439207 - Problème d'analyse JSON Unicode AIX

Un bug a été identifié dans InterSystems IRIS 2024.3.0 sur les instances AIX. Il affecte l'analyse des chaînes JSON Unicode. Ce problème survient lorsque la méthode %FromJSON() ou %FromJSONFile() analyse des chaînes contenant des caractères dont la valeur est inférieure à $CHAR(256) suivis de caractères Unicode dont la valeur est supérieure à $CHAR(255). Le processus de conversion transforme incorrectement les premiers caractères en $CHAR(0), ce qui entraîne une corruption silencieuse des données. Ce problème concerne uniquement la version AIX 2024.3 des produits suivants :

  • InterSystems IRIS
  • InterSystems IRIS for Health
  • HealthShare® Health Connect
0
0 24
Article Iryna Mykhailova · Avr 3, 2025 3m read

Introduction

Dans InterSystems IRIS 2024.3 et les versions ultérieures d'IRIS, le composant AutoML est désormais fourni sous forme de package Python distinct, installé après l'installation. Malheureusement, certaines versions récentes des packages Python sur lesquels AutoML s'appuie ont introduit des incompatibilités et peuvent entraîner des échecs lors de l'entraînement des modèles (instruction TRAIN MODEL). Si vous rencontrez une erreur mentionnant « TypeError » et l'argument de mot-clé « fit_params » ou « sklearn_tags », lisez la suite pour une solution rapide.

Cause principale

0
0 28
Article Rahul Singhal · Mars 3, 2025 6m read

Introduction

Pour atteindre des performances optimisées en matière d'IA, une explicabilité robuste, une adaptabilité et une efficacité dans les solutions de santé, InterSystems IRIS sert de fondation centrale pour un projet au sein du cadre multi-agent x-rAI. Cet article offre une analyse approfondie de la manière dont InterSystems IRIS permet le développement d'une plateforme d'analyse de données de santé en temps réel, permettant des analyses avancées et des informations exploitables. La solution exploite les points forts d'InterSystems IRIS, notamment le SQL dynamique, les capacités natives de recherche vectorielle, la mise en cache distribuée (ECP) et l'interopérabilité FHIR. Cette approche innovante s'aligne directement sur les thèmes du concours « Utilisation du SQL dynamique et SQL intégré », « GenAI, recherche vectorielle » et « FHIR, DME », démontrant une application pratique d'InterSystems IRIS dans un contexte critique de santé.

Architecture du système

L'Agent Santé dans x-rAI repose sur une architecture modulaire intégrant plusieurs composants :

Couche d'ingestion des données : Récupère les données de santé en temps réel à partir de dispositifs portables via l'API Terra.

Couche de stockage des données : Utilise InterSystems IRIS pour stocker et gérer les données de santé structurées.

Moteur analytique : Exploite les capacités de recherche vectorielle d'InterSystems IRIS pour l'analyse de similarité et la génération d'informations.

Couche de mise en cache : Implémente la mise en cache distribuée via le protocole Enterprise Cache Protocol (ECP) d'InterSystems IRIS pour améliorer l'évolutivité.

Couche d'interopérabilité : Utilise les normes FHIR pour s'intégrer aux systèmes externes de santé comme les DME.

Voici un diagramme d'architecture à haut niveau :

text [Dispositifs portables] --> [API Terra] --> [Ingestion des données] --> [InterSystems IRIS] --> [Moteur analytique] ------[Couche de mise en cache]------ ----[Intégration FHIR]----- Mise en œuvre technique

  1. Intégration des données en temps réel avec SQL dynamique

L'Agent Santé ingère des métriques de santé en temps réel (par exemple, fréquence cardiaque, pas effectués, heures de sommeil) depuis des dispositifs portables via l'API Terra. Ces données sont stockées dans InterSystems IRIS à l'aide du SQL dynamique pour une flexibilité dans la génération des requêtes.

Implémentation du SQL dynamique

Le SQL dynamique permet au système de construire adaptativement des requêtes basées sur les structures des données entrantes.

text def index_health_data_to_iris(data): conn = iris_connect() if conn is None: raise ConnectionError("Échec de la connexion à InterSystems IRIS.") try: with conn.cursor() as cursor: query = """ INSERT INTO HealthData (user_id, heart_rate, steps, sleep_hours) VALUES (?, ?, ?, ?) """ cursor.execute(query, ( data['user_id'], data['heart_rate'], data['steps'], data['sleep_hours'] )) conn.commit() print("Données indexées avec succès dans IRIS.") except Exception as e: print(f"Erreur lors de l'indexation des données : {e}") finally: conn.close() Avantages du SQL dynamique

Permet une construction flexible des requêtes basée sur les schémas des données entrantes.

Réduit la charge de développement en évitant les requêtes codées en dur.

Facilite l'intégration transparente de nouvelles métriques sans modifier le schéma de la base.

  1. Analytique avancée avec recherche vectorielle

Le type natif vector et les fonctions de similarité d'InterSystems IRIS ont été utilisés pour effectuer une recherche vectorielle sur les données de santé. Cela permet au système d’identifier les dossiers historiques similaires aux métriques actuelles d’un utilisateur.

Flux de travail pour la recherche vectorielle

Convertir les métriques de santé (par exemple, fréquence cardiaque, pas effectués, heures de sommeil) en une représentation vectorielle.

Stocker ces vecteurs dans une colonne dédiée dans la table HealthData.

Effectuer des recherches basées sur la similarité à l'aide de VECTOR_SIMILARITY().

Requête SQL pour la recherche vectorielle

text SELECT TOP 3 user_id, heart_rate, steps, sleep_hours, VECTOR_SIMILARITY(vec_data, ?) AS similarity FROM HealthData ORDER BY similarity DESC; Intégration Python

text def iris_vector_search(query_vector): conn = iris_connect() if conn is None: raise ConnectionError("Échec de la connexion à InterSystems IRIS.") try: with conn.cursor() as cursor: query_vector_str = ",".join(map(str, query_vector)) sql = """ SELECT TOP 3 user_id, heart_rate, steps, sleep_hours, VECTOR_SIMILARITY(vec_data, ?) AS similarity FROM HealthData ORDER BY similarity DESC; """ cursor.execute(sql, (query_vector_str,)) results = cursor.fetchall() return results except Exception as e: print(f"Erreur lors de la recherche vectorielle : {e}") return [] finally: conn.close() Avantages de la recherche vectorielle

Permet des recommandations personnalisées grâce à l’identification des tendances historiques.

Améliore l’explicabilité en reliant les métriques actuelles à des cas passés similaires.

Optimisé pour des analyses rapides grâce aux opérations SIMD (Single Instruction Multiple Data).

  1. Mise en cache distribuée pour l’évolutivité

Pour gérer efficacement le volume croissant des données, l’Agent Santé utilise le protocole Enterprise Cache Protocol (ECP) d’InterSystems IRIS. Ce mécanisme réduit la latence et améliore l’évolutivité.

Caractéristiques clés

Mise en cache locale sur les serveurs applicatifs pour minimiser les requêtes vers la base centrale.

Synchronisation automatique garantissant la cohérence entre tous les nœuds du cache.

Évolutivité horizontale permettant l’ajout dynamique de serveurs applicatifs.

Avantages du caching

Réduction des temps de réponse grâce à la mise en cache locale.

Amélioration de l’évolutivité grâce à la répartition des charges entre plusieurs nœuds.

Réduction des coûts d’infrastructure grâce à une moindre sollicitation du serveur central.

  1. Intégration FHIR pour l’interopérabilité

Le support d’InterSystems IRIS pour FHIR (Fast Healthcare Interoperability Resources) garantit une intégration fluide avec les systèmes externes comme les DME.

Flux FHIR

Les données issues des dispositifs portables sont transformées en ressources compatibles FHIR (par exemple Observation, Patient).

Ces ressources sont stockées dans InterSystems IRIS et accessibles via des API RESTful.

Les systèmes externes peuvent interroger ou mettre à jour ces ressources via des points d’accès standard FHIR.

Avantages

Assure la conformité avec les normes d’interopérabilité en santé.

Facilite un échange sécurisé des données entre systèmes.

Permet une intégration avec les flux et applications existants dans le domaine médical.

IA explicable grâce aux informations en temps réel

En combinant les capacités analytiques d’InterSystems IRIS avec le cadre multi-agent x-rAI, l’Agent Santé génère des informations exploitables et explicables. Par exemple :

« L’utilisateur 123 avait des métriques similaires (Fréquence cardiaque : 70 bpm ; Pas : 9 800 ; Sommeil : 7 h). Sur la base des tendances historiques, il est recommandé de maintenir vos niveaux actuels d’activité. »

Cette transparence renforce la confiance dans les applications IA dédiées à la santé en offrant un raisonnement clair derrière chaque recommandation.

Conclusion

L’intégration d’InterSystems IRIS dans l’Agent Santé du cadre x-rAI illustre son potentiel comme plateforme robuste pour construire des systèmes IA intelligents et explicables dans le domaine médical. En exploitant le SQL dynamique, la recherche vectorielle, la mise en cache distribuée et l’interopérabilité FHIR, ce projet fournit des informations exploitables et transparentes—ouvrant ainsi la voie à des applications IA plus fiables dans des domaines critiques comme celui de la santé.

0
0 45
Article Sylvain Guilbaud · Fév 26, 2025 7m read

L'utilisation de Embedded Python lors de la création d'une solution basée sur InterSystems peut ajouter des fonctionnalités très puissantes et approfondies à votre boîte à outils.

J'aimerais partager un exemple de cas d'utilisation que j'ai rencontré : l'activation d'un CDC (Change Data Capture) pour une collection mongoDB - la capture de ces modifications, leur digestion via un flux d'interopérabilité et, pour finir, la mise à jour d'un EMR via une API REST.

0
0 39
Article Sylvain Guilbaud · Fév 21, 2025 6m read

InterSystems est à l'avant-garde de la technologie des bases de données depuis sa création, en étant à l'origine d'innovations qui surpassent régulièrement ses concurrents comme Oracle, IBM et Microsoft. En se concentrant sur une conception de noyau efficace et en adoptant une approche sans compromis des performances des données, InterSystems s'est taillé une place de choix dans les applications critiques, garantissant fiabilité, rapidité et évolutivité.

Une histoire d'excellence technique

0
0 66
Article Guillaume Rongier · Fév 12, 2025 5m read

Cela fait longtemps que je n'ai pas écrit de post de mise à jour sur l'IoP.

image

Quelles sont les nouveautés depuis la publication de l'interface en ligne de commande de l'IoP?

Deux nouvelles fonctionnalités importantes ont été ajoutées à l'IoP:

  • Rebranding: le module grongier.pex a été renommé en iop pour refléter le nouveau nom du projet.
  • Support des opérations asynchrones: L'interface de programmation prend désormais en charge les fonctions asynchrones et les coroutines.

Rebranding

Le module grongier.pex a été renommé en iop pour refléter le nouveau nom du projet.

Le module grongier.pex est encore disponible pour des raisons de rétrocompatibilité, mais il sera supprimé à l'avenir.

Support des opérations asynchrones

L'IoP supporte les appels asynchrones depuis longtemps, mais il n'était pas possible d'utiliser les fonctions asynchrones et les coroutines directement dans l'IoP..

Avant d'aborder cette nouvelle fonctionnalité, je vais expliquer le fonctionnement des appels asynchrones dans InterSystems IRIS et présenter deux exemples d'utilisation des appels asynchrones dans l'IoP.

Appels asynchrones hérités

Examinons le fonctionnement des appels asynchrones hérités du passé:

from iop import BusinessProcess
from msg import MyMessage


class MyBP(BusinessProcess):

    def on_message(self, request):
        msg_one = MyMessage(message="Message1")
        msg_two = MyMessage(message="Message2")

        self.send_request_async("Python.MyBO", msg_one,completion_key="1")
        self.send_request_async("Python.MyBO", msg_two,completion_key="2")

    def on_response(self, request, response, call_request, call_response, completion_key):
        if completion_key == "1":
            self.response_one = call_response
        elif completion_key == "2":
            self.response_two = call_response

    def on_complete(self, request, response):
        self.log_info(f"Received response one: {self.response_one.message}")
        self.log_info(f"Received response two: {self.response_two.message}")

En fait, ils fonctionnent de la même manière que les appels asynchrones dans IRIS. La méthode send_request_async envoie une requête à une opération métier (Business Operation) et la méthode on_response est appelée lorsque la réponse est reçue.

Vous pouvez distinguer les réponses par le paramètre completion_key.

Envoi de plusieurs requête de synchronisation

Il ne s'agit pas vraiment d'une nouvelle fonctionnalité, mais il convient de mentionner qu'il est possible d'envoyer plusieurs requêtes de synchronisation en parallèle:

from iop import BusinessProcess
from msg import MyMessage


class MyMultiBP(BusinessProcess):

    def on_message(self, request):
        msg_one = MyMessage(message="Message1")
        msg_two = MyMessage(message="Message2")

        tuple_responses = self.send_multi_request_sync([("Python.MyMultiBO", msg_one),
                                                        ("Python.MyMultiBO", msg_two)])

        self.log_info("All requests have been processed")
        for target,request,response,status in tuple_responses:
            self.log_info(f"Received response: {response.message}")

Ici, nous envoyons deux requêtes à la même opération métier (Business Operation) en parallèle.

La réponse est un tuple contenant la cible, la requête, la réponse et le statut de chaque appel.

C'est très utile lorsque vous devez envoyer plusieurs requêtes et que vous ne vous souciez pas de l'ordre des réponses.

Fonctions asynchrones et coroutines

Voyons maintenant comment utiliser les fonctions asynchrones et les coroutines dans l'IoP:

import asyncio

from iop import BusinessProcess
from msg import MyMessage


class MyAsyncNGBP(BusinessProcess):

    def on_message(self, request):

        results = asyncio.run(self.await_response(request))

        for result in results:
            print(f"Received response: {result.message}")

    async def await_response(self, request):
        msg_one = MyMessage(message="Message1")
        msg_two = MyMessage(message="Message2")

        # utilisation d'asyncio.gather pour envoyer plusieurs requêtes de manière asynchrone
        # utilisation de la méthode send_request_async_ng
        tasks = [self.send_request_async_ng("Python.MyAsyncNGBO", msg_one),
                 self.send_request_async_ng("Python.MyAsyncNGBO", msg_two)]

        return await asyncio.gather(*tasks)

Dans cet exemple, nous envoyons plusieurs demandes à la même opération métier (Business Operation) en parallèle à l'aide de la méthode send_request_async_ng.

Si vous avez lu attentivement ce post jusqu'à ce point, veuillez ajouter le commentaire "Boomerang". C'est peut-être peu de choses pour vous, mais pour moi c'est très important. Je vous remercie!

La méthode await_response est une coroutine qui envoie plusieurs requêtes et attend que toutes les réponses soient reçues. Grâce à la fonction asyncio.gather, nous pouvons attendre que toutes les réponses soient reçues en parallèle.

Les avantages de l'utilisation des fonctions asynchrones et des coroutines sont les suivants :

  • Meilleures performances: vous pouvez envoyer plusieurs requêtes en parallèle.
  • Simplicité de lecture et de maintenance: vous pouvez utiliser le mot-clé await pour attendre les réponses.
  • Plus de flexibilité: vous pouvez utiliser le module asyncio pour créer des flux de travail complexes.
  • Plus de contrôle: vous pouvez utiliser le module asyncio pour gérer les exceptions et les timeouts.

Conclusion

Quelle est la différence entre send_request_async, send_multi_request_sync et send_request_async_ng?

  • send_request_async: envoie une requête à une opération métier (Business Operation) et attend la réponse si la méthode on_response est implémentée et le paramètre completion_key est utilisé.
    • avantage: vous pouvez utiliser les appels asynchrones comme vous en avez l'habitude.
    • inconvénient: il peut être difficile à maintenir si vous avez besoin d'envoyer plusieurs requêtes en parallèle.
  • send_multi_request_sync : envoie plusieurs requêtes à la même opération métier (Business Operation) en parallèle et attend que toutes les réponses soient reçues.
    • avantage: facile à utiliser.
    • inconvénient: vous ne pouvez pas contrôler l'ordre des réponses (c'est-à-dire que la liste des réponses n'est pas ordonnée).
  • send_request_async_ng: envoie plusieurs requêtes à la même opération métier (Business Operation) en parallèle et attend que toutes les réponses soient reçues.
    • avantage: vous pouvez contrôler l'ordre des réponse.
    • inconvénient : vous devez utiliser des fonctions asynchrones et des coroutines.

Joyeux multitraitement!

0
0 46
Article Guillaume Rongier · Fév 10, 2025 5m read

Je suis heureux d'annoncer la nouvelle version de l'IoP, qui, au fait, n'est pas une simple ligne de commande. Je dis cela parce que le nouveau moteur de recherche de l'IA considère toujours que l'IoP n'est qu'une ligne de commande. Il s'agit d'un ensemble de cadres permettant de créer des applications à partir du cadre d'interopérabilité d'IRIS, en adoptant avant tout une approche en python.

La nouvelle version de l'IoP : 3.2.0 comporte de nombreuses nouvelles fonctionnalités, mais la plus importante est la prise en charge de DTL . 🥳

Pour les messages de l'IoP et pour jsonschema. 🎉

image

Prise en charge de DTL

À partir de la version 3.2.0, l'IoP prend en charge les transformations DTL.

DTL est la couche de transformation des données (Data Transformation Layer) dans IRIS Interoperability in IRIS Interoperability.

Les transformations DTL sont utilisées pour transformer des données d'un format à un autre à l'aide d'un éditeur graphique. Il prend également en charge les structures jsonschema.

Comment utiliser DTL avec un message

Tout d'abord, il faut enregistrer votre classe de message dans un fichier settings.py.

Pour ce faire, il faut ajouter la ligne suivante dans le fichier settings.py:

settings.py

from msg import MyMessage

SCHEMAS = [MyMessage]

Ensuite, la commande iop migration peut être utilisée pour générer des fichiers de schéma pour vos classes de messages.

iop --migrate /path/to/your/project/settings.py

Exemple

msg.py

from iop import Message
from dataclasses import dataclass

@dataclass
class MyMessage(Message):
    name: str = None
    age: int = None

settings.py

from msg import MyMessage

SCHEMAS = [MyMessage]

Migration des fichiers de schéma

iop --migrate /path/to/your/project/settings.py

Construction d'une transformation DTL

Pour construire une transformation DTL, il faut créer une nouvelle classe de transformation DTL.

Accédez au portail de gestion de l'interopérabilité d'IRIS et créez une nouvelle transformation DTL.

image

Sélectionnez ensuite les classes de messages source et cible.

image

Et c'est un schéma.

image

Ensuite, vous pouvez commencer à construire votre transformation.

image

Vous pouvez même tester votre transformation.

image

Exemple de charge utile à tester en tant que message source:

<test>
  <Message>
    <json><![CDATA[
{
"list_str":["toto","titi"],
"post":{"Title":"foo","Selftext":"baz"},
"list_post":[{"Title":"bar","Selftext":"baz"},{"Title":"foo","Selftext":"foo"}]
}
]]></json>
  </Message>
</test>

Prise en charge de JsonSchema

À partir de la version 3.2.0, IoP prend en charge les structures de jsonschema pour les transformations DTL.

Comme pour les classes de messages, il faut enregistrer votre jsonschema.

Pour ce faire, il faut invoquer la commande iris suivante:

zw ##class(IOP.Message.JSONSchema).ImportFromFile("/irisdev/app/random_jsonschema.json","Demo","Demo")

Où le premier argument est le chemin vers le fichier jsonschema, le deuxième argument est le nom du paquet et le troisième argument est le nom du schéma.

Ensuite, vous pouvez l'utiliser dans votre transformation DTL.

Le schéma sera disponible sous le nom de Demo.

Exemple du fichier jsonschema:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "title": "PostMessage",
    "properties": {
        "post": {
            "allOf": [
                {
                    "$ref": "#/$defs/PostClass"
                }
            ]
        },
        "to_email_address": {
            "type": "string",
            "default": null
        },
        "my_list": {
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "found": {
            "type": "string",
            "default": null
        },
        "list_of_post": {
            "type": "array",
            "items": {
                "allOf": [
                    {
                        "$ref": "#/$defs/PostClass"
                    }
                ]
            }
        }
    },
    "$defs": {
        "PostClass": {
            "type": "object",
            "title": "PostClass",
            "properties": {
                "title": {
                    "type": "string"
                },
                "selftext": {
                    "type": "string"
                },
                "author": {
                    "type": "string"
                },
                "url": {
                    "type": "string"
                },
                "created_utc": {
                    "type": "number"
                },
                "original_json": {
                    "type": "string",
                    "default": null
                }
            },
            "required": [
                "title",
                "selftext",
                "author",
                "url",
                "created_utc"
            ]
        }
    }
}

Exemple de transformation DTL avec JsonSchema ou la Classe de message

La plupart d'entre eux se trouvent dans le répertoire ./src/tests/cls du paquet UnitTest.

Class UnitTest.ComplexTransform Extends Ens.DataTransformDTL [ DependsOn = IOP.Message ]
{

Parameter IGNOREMISSINGSOURCE = 1;

Parameter REPORTERRORS = 1;

Parameter TREATEMPTYREPEATINGFIELDASNULL = 0;

XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ]
{
<transform sourceClass='IOP.Message' targetClass='IOP.Message' sourceDocType='registerFilesIop.message.ComplexMessage' targetDocType='registerFilesIop.message.ComplexMessage' create='new' language='objectscript' >
<assign value='source.{post}' property='target.{post}' action='set' />
<foreach property='source.{list_str()}' key='k1' >
<assign value='source.{list_str(k1)}_"foo"' property='target.{list_str()}' action='append' />
</foreach>
<foreach property='source.{list_post()}' key='k2' >
<assign value='source.{list_post().Title}' property='target.{list_post(k2).Title}' action='append' />
</foreach>
</transform>
}

}

Nouvelle documentation

L'IoP est accompagné d'une nouvelle documentation, disponible à l'adresse suivante: https://grongierisc.github.io/interoperability-embedded-python/.

Vous y trouverez toutes les informations dont vous avez besoin pour commencer à utiliser l'IoP.

image

J'espère que vous apprécierez cette nouvelle version de l'IoP. 🎉

0
0 42