#ObjectScript

0 Abonnés · 105 Publications

InterSystems ObjectScript est un langage de script permettant d'opérer avec des données en utilisant n'importe quel modèle de données de la plateforme de données InterSystems (objets, relationnel, clé-valeur, document, globales) et de développer une logique métier pour les applications côté serveur sur la plateforme de données InterSystems.

Documentation.

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 Lorenzo Scalese · Oct 6, 2025 5m read

Commençons par une question simple et motivante : au cours des 14 derniers jours, quelles sont les erreurs les plus courantes dans le Journal des erreurs d'application?

Répondre à cette question via le portail de gestion ou le terminal est un processus manuel fastidieux. Nous devrions pouvoir simplement utiliser SQL. Heureusement, quelques requêtes de classe sont disponibles  pour vous aider dans la classe SYS.ApplicationError de l'espace de noms %SYS. Vous pouvez répondre à cette question pour une seule date à l'aide d'une commande telle que:

select"Error message",count(*)
from SYS.ApplicationError_ErrorList('CCR','12/16/2024')
groupby"Error message"orderby2desc

Malheureusement, la structure des requêtes de classe est soumise aux mêmes contraintes structurelles générales que les pages du portail de gestion ; la requête ErrorList nécessite un espace de noms et une date. Il existe sûrement une meilleure approche que de faire 14 appels conjoints à cette requête de classe pour différentes dates, n'est-ce pas ? D'une certaine manière, c'est un véritable problème. S'il existe une bonne façon de procéder avec du SQL classique et que je l'ai simplement manquée, merci de me le faire savoir!

Logiquement, il convient de rédiger notre propre requête de classe personnalisée. Cela implique d'ajouter un membre de classe Query (par exemple <QueryName>) et d'implémenter des méthodes nommées <QueryName>Execute, <QueryName>Fetch et <QueryName>Close. De manière générale, la méthode Execute configure le contexte de la requête de classe et effectue toutes les tâches initiales, en conservant l'état dans qHandle. La méthode Fetch récupère une seule ligne et indique si toutes les lignes ont été trouvées ou non. Enfin, la méthode Close effectue le nettoyage final. Par exemple, si l'implémentation des méthodes Execute/Fetch utilise une variable globale privée au processus, la méthode Close peut la supprimer.

N'oubliez pas d'ajouter un indicateur [ SqlProc ] magique au membre Query afin qu'il puisse être appelé en tant que TVF (fonction table) à partir d'autres requêtes SQL!

Ci-dessous, vous trouverez un exemple complet fonctionnel:

/// Requêtes utilitaires pour aider à accéder au journal des erreurs de l'application à partir de SQLClass AppS.Util.ApplicationErrorLog
{

/// Renvoi de toutes les erreurs d'application (toutes dates confondues) à partir du journal des erreurs d'application Query All() As%Query(ROWSPEC = "Date:%Date,ErrorNumber:%Integer,ErrorMessage:%String,Username:%String") [ SqlProc ] { }

/// Récupèration d'une liste de dates comportant des erreurs et la stocke dans qHandleClassMethod AllExecute(ByRef qHandle As%Binary) As%Status { Set ns = $NamespaceNew$NamespaceSet$Namespace = "%SYS"Set stmt = ##class(%SQL.Statement).%New() Set stmt.%SelectMode = 0Set result = ##class(%SQL.Statement).%ExecDirect(stmt,"select %DLIST(""Date"") ""Dates"" from SYS.ApplicationError_DateList(?)",ns) $$$ThrowSQLIfError(result.%SQLCODE,result.%Message) If 'result.%Next(.sc) { Return sc } Set qHandle("list") = result.%Get("Dates") Set qHandle("pointer") = 0Quit$$$OK }

/// Récupèreation de la ligne suivante, en passant à la date suivante si nécessaireClassMethod AllFetch(ByRef qHandle As%Binary, ByRef Row As%List, ByRef AtEnd As%Integer = 0) As%Status [ PlaceAfter = AllExecute ] { Set sc = $$$OKSet ns = $NamespaceNew$NamespaceSet$Namespace = "%SYS"If$Get(qHandle("dateResult")) = "" { // Passage à la date suivanteSet pointer = qHandle("pointer") If '$ListNext(qHandle("list"),pointer,oneDate) { Set AtEnd = 1Quit$$$OK } Set qHandle("pointer") = pointer Set qHandle("currentDate") = oneDate Set qHandle("dateResult") = ##class(%SQL.Statement).%ExecDirect(,"select * from SYS.ApplicationError_ErrorList(?,?)",ns,oneDate) $$$ThrowSQLIfError(qHandle("dateResult").%SQLCODE,qHandle("dateResult").%Message) } If qHandle("dateResult").%Next(.sc) { // Si nous avons une ligne pour la date actuelle, ajoutons-laSet Row = $ListBuild(qHandle("currentDate"),qHandle("dateResult").%GetData(1),qHandle("dateResult").%GetData(2),qHandle("dateResult").%GetData(6)) } ElseIf$$$ISOK(sc) { // Sinon, il faut vider le jeu de résultats et appeler AllFetch pour avancerSet qHandle("dateResult") = ""Set$Namespace = ns Set sc = ..AllFetch(.qHandle,.Row,.AtEnd) } Quit sc }

ClassMethod AllClose(ByRef qHandle As%Binary) As%Status [ PlaceAfter = AllExecute ] { New$NamespaceSet$Namespace = "%SYS"// Il semble parfois nécessaire pour que %OnClose s'exécute correctementKill qHandle("dateResult") Quit$$$OK }

}

Dans cet exemple, nous commençons dans un espace de noms utilisateur, mais toutes les requêtes s'exécutent en réalité dans %SYS. Execute obtient une liste des dates d'erreur pour l'espace de noms actuel et la stocke dans qHandle. Fetch passe à la date suivante lorsque cela est approprié, puis renvoie l'erreur suivante pour la date actuelle. Et Close s'assure que la requête de classe sort de la portée dans %SYS, car j'obtenais parfois des erreurs si ce n'était pas le cas. C'était un peu surprenant, mais cela semble logique, car la requête de classe que nous appelons n'existe que dans %SYS.

La réutilisabilité des fonctions table offre de nombreuses possibilités. Par exemple, nous pouvons en ajouter une autre dans la même classe:

/// Obtenir le nombre d'erreurs survenues au cours des derniers <var>Days</var> jours
Query ErrorCounts(Days As%Integer) As%SQLQuery(ROWSPEC = "Occurrences:%Integer,ErrorMessage:%String") [ SqlProc ]
{
    SELECT COUNT(*) AS Occurrences, ErrorMessage
    FROM AppS_Util.ApplicationErrorLog_All()
    WHERE DATEDIFF(D,"Date",$h) <= :Days
    GROUP BY ErrorMessage
    ORDER BY Occurrences DESC
}

Et maintenant, pour obtenir les erreurs d'application les plus courantes au cours des 14 derniers jours, il suffit de:

call AppS_Util.ApplicationErrorLog_ErrorCounts(14)

Maintenant, il ne nous reste plus qu'à les corriger! 😅

0
0 18
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 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 Eugene.Forde · Sept 4, 2025 4m read

Salut tout le monde !

Parfois, lorsqu’on conçoit une méthode de classe et qu’on y ajoute de plus en plus de fonctionnalités utiles, le nombre de paramètres peut rapidement atteindre 10, voire plus.

Cela devient alors assez difficile pour les utilisateurs de ces méthodes utiles de se rappeler de la position des paramètres importants, et il devient très facile de se tromper en inversant des valeurs entre paramètres.

Voici un exemple d’une telle méthode (j’ai demandé à GPT de me créer une méthode avec 20 paramètres) :

ClassMethod GenerateReportWith20Params(
    pTitle As%String = "",
    pAuthor As%String = "",
    pDate As%String = "",            // ex. 2025-09-03
    pCompany As%String = "",
    pDepartment As%String = "",
    pVersion As%String = "1.0",
    pFormat As%String = "pdf",      // pdf|html|docx
    pIncludeCharts As%Boolean = 1,
    pIncludeSummary As%Boolean = 1,
    pIncludeAppendix As%Boolean = 0,
    pConfidentiality As%String = "Public",
    pLanguage As%String = "en",
    pReviewers As%String = "",      // CSV, ex. "Alice,Bob"
    pApprover As%String = "",
    pLogoPath As%String = "",
    pWatermarkText As%String = "",
    pColorScheme As%String = "default",
    pPageSize As%String = "A4",
    pOrientation As%String = "Portrait",
    pOutputPath As%String = "report.pdf"
) As%Status
{
    // implémentation
}
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 Lorenzo Scalese · Août 27, 2025 4m read

Cet excellent article a récemment déclenché une discussion privée, et j'aimerais partager certaines de mes réflexions à ce sujet.
La question motivante se résume ainsi : pourquoi devons-nous absolument établir des règles ou des conventions de codage ? Où est passée la merveilleuse époque des artistes-programmeurs de la Renaissance qui traçaient leur propre voie, avant d'être supplantés par les artisans, puis (pire encore) par IA?
En bref, il existe plusieurs raisons pour expliquer l'utilité des normes et des directives de codage, et les artistes-programmeurs de la Renaissance n'ont pas complètement disparu.

Raison 1: De nos jours, lorsque vous enseignez à un artiste, à un peintre débutant, vous commencez par lui demander de colorier à l'intérieur des lignes. Ce peintre sera peut-être brillant un jour, mais pas encore. Si vous voulez apprendre à créer des œuvres d'art, vous devez d'abord faire cela, puis apprendre progressivement les techniques et les concepts des maîtres. Ensuite, si vous êtes vraiment doué ou si vous avez beaucoup de chance, vous pourrez développer votre propre style et créer quelque chose de nouveau que le reste du monde voudra imiter. Mais vous devez commencer par suivre les règles.

(remarque: j'ai trouvé cela sur l'Internet ; aucun de mes enfants ne sait encore faire ça.)

Raison 2: Si vous travaillez dans un domaine où votre créativité doit s'intégrer à celle des autres, comme dans un ouvrage de patchwork, vous devez établir certaines règles, sans quoi votre œuvre ne fonctionnera pas, car les pièces ne s'emboîteront jamais. Vous pouvez soit convenir du principe selon lequel "nous faisons tous des carrés de 40 cm", soit travailler encore plus étroitement et en collaboration avec un groupe d'autres personnes, ce qui n'est peut-être pas la meilleure option pour un artiste solitaire qui passe quatre ans à peindre un plafond. (Surtout si ses responsables décident de faire appel à quelques autres artistes solitaires pour "l'aider.”)

(C'est ChatGPT qui m'a inspiré cette image. Toutes mes excuses aux artistes réels.)

Raison 3: Si vous travaillez sur un élément de codage existant, particulièrement ancien ou particulièrement génial, vous êtes souvent confronté à un dilemme : comprendre et accepter l'intention et l'élégance de la conception et de l'exécution de l'auteur , ou simplement dire "C'est moi le responsable maintenant, on va tout jeter et faire à ma façon." Je vais vous donner un exemple : une application web sur laquelle j'ai travaillé se sert beaucoup de "pages XML" où un trio (pageName.xml, pageName.js, pageName.mac) forme une page. Le fichier pageName.xml était, jusqu'à récemment, probablement écrit dans cet étrange dialecte "WD-xsl" qui ressemble beaucoup au XSLT standard mais qui ne fonctionne que dans Internet Explorer Microsoft Edge s'il se fait passer pour IE5. Le fichier pageName.js contient probablement environ 40 fois plus de "frame" que nécessaire et comfortable. Le fichier pageName.mac est probablement rempli de syntaxe à points, de commandes abrégées et de macros incohérentes. Si vous êtes un développeur débutant, vous pleurez et vous fuyez parce que cela n'a aucun sens. Si vous êtes un développeur expérimenté, vous lisez le code, vous essayez de le comprendre, puis vous décidez que “c'est dégoûtant, je vais faire mieux autrement” – mais alors la personne qui travaillera ensuite sur l'application devra apprendre le paradigme original et votre nouveau paradigme astucieux. Faites cela pendant 20 ans, et un véritable cauchemar vous attend. Mais si vous êtes vraiment un artiste expert, vous pouvez vous lancer dans la restauration artistique: observez l'élégance de la structure d'origine et travaillez en respectant celle-ci, en corrigeant délicatement les éléments architecturaux sans importance qui font pleurer le nouveau développeur et poussent le développeur senior à appuyer sur "Supprimer" sans risquer de créer un chaos fragmenté ou de passer des années  à tout repeindre. Peut-être même réaliserez-vous vos propres œuvres dans le style du grand maître. La leçon la plus importante à tirer de ce conte est qu'en tant qu'artiste véritable, vous êtes tout à fait intéressé à produire un travail d'une telle qualité que quelqu'un qui en hériterait sans passer des années pour s'entraîner ne déciderait pas de tout jeter. Les "petites choses" comme le style de code, la lisibilité et la gestion de la dette technique contribuent grandement à préserver l'architecture et même chaque ligne de code.

En bref:

  • Les règles et les conventions nous permettent de former de nouveaux artistes brillants bien avant qu'ils ne le deviennent
  • Les règles et les conventions nous offrent un cadre fixe dans lequel nous pouvons exercer notre créativité sans perdre de temps à essayer de nous entendre avec les autres
  • Les règles et les conventions nous permettent de créer quelque chose de beau qui ne sera pas abandonné par la première personne qui en héritera
0
0 17
InterSystems officiel Adeline Icard · Juil 22, 2025

InterSystems a le plaisir d'annoncer la sortie de la version 3.0.5 de l'extension VS Code - ObjectScript. Cette version inclut de nombreuses corrections de bugs, ainsi que des modifications des données de télémétrie collectées. La collecte de données d'utilisation supplémentaires permet à InterSystems d'identifier et de prioriser les correctifs et améliorations les plus bénéfiques pour vous, nos utilisateurs. Les informations personnelles identifiables (PII) ne seront jamais collectées et la télémétrie peut être désactivée via le paramètre telemetry.telemetryLevel. La liste complète des

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 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 Lorenzo Scalese · Juin 18, 2025 5m read

Le bon vieux temps

La classe %Library.DynamicObject existe dans IRIS depuis bien avant que IRIS ne devienne IRIS. Si vous l'utilisez depuis l'époque de Cache, vous souhaiterez peut-être vous familiariser avec certaines de ses modifications.

Dans Cache 2018, la méthode %Get n'avait qu'un seul argument. Il s'agissait de la clé permettant de récupérer les données dans le JSON. Ainsi, si votre objet JSON s'appelait myObj, cela ressemblerait à ceci:

{
    “mybool”:true,
    “mynum”:1234,
    “mystring”:”Hello World!”
}

L'exploitation de myObj.%Get(“mybool”) renverrait 1, myObj.%Get(“mynum”) renverrait 1234 et myObj.%Get("mystring") renverrait la chaîne "Hello World!" 

La définition de ces paramètres, en revanche, nécessitait un peu plus de travail. Par exemple, l'attribution d'une propriété JSON à 0 pouvait signifier le nombre 0, une valeur booléenne signifiant faux ou une chaîne littérale "0". C'est pourquoi la méthode %Set avait toujours un troisième argument facultatif. Pour créer l'objet JSON mentionné ci-dessus, nous pouvions utiliser le code suivant:

set myObj = ##class(%Library.DynamicObject).%New()
do myObj.%Set(“mybool”,1,”boolean”)
do myObj.%Set(“mynum”,1234,”number”)
do myObj.%Set(“mystring”,”Hello World!”,”string”)

Cependant, dans ce cas, nous pourrions également omettre le troisième argument des deux derniers. Ainsi, 1234 serait reconnu comme un nombre, car il n'est pas entre guillemets, tandis que "Hello World!" serait identifié comme une chaîne, car il est entre guillemets. Si nous voulions ajouter la valeur 1234 à l'objet en tant que chaîne, nous pourrions changer la chaîne en nombre. Nous pourrions également spécifier le type "null". Dans ce cas, la valeur doit être "". En pratique, cependant, nous ajoutons souvent ces valeurs à partir de variables dans notre code ObjectScript. Pour cette raison, il peut être préférable de spécifier cet argument, juste au cas où la variable serait une chaîne ou un nombre, afin de garantir que notre JSON arrive à destination correctement encodé.

Comment j'ai appris à ne plus m'inquiéter à propos de <MAXSTRING> et aimer JSON

Comme l'a dit un jour le sage Billy Joel, ""Le bon vieux temps n'était pas toujours bon, demain n'est pas aussi mauvais qu'il n'y paraît." La liste des types pour %Set s'est allongée, et la méthode %Get a acquis deux nouveaux arguments. Ce qui est crucial, c'est qu'elles prennent toutes deux en charge le type "stream". Si vous avez déjà traité de grandes quantités de données JSON, vous avez probablement déjà rencontré une erreur lorsque les données contenues dans le JSON dépassaient la longueur maximale autorisée pour une chaîne dans IRIS. La nouvelle méthode %Get vous permet de spécifier deux arguments supplémentaires, une valeur par défaut et un type. Votre ancien code continue toutefois de fonctionner, car ces deux arguments sont facultatifs et, s'ils sont omis, les méthodes fonctionnent exactement comme en 2018. Si rien n'est trouvé pour la clé donnée, la valeur par défaut est renvoyée. La fonction type fonctionne de manière similaire à l'argument type de la méthode %Set. Vous pouvez également spécifier le type de données que vous récupérez. Prenons l'exemple suivant du bloc try/catch:

try{
    Set mydata = myObj.%Get(“mydata”,”N/A”)
}
catch ex{
    if ex.Name = “<MAXSTRING>”{
        set mydata = myObj.%Get(“mydata”,,”stream”)
    }
}

Il tentera de définir mydata à la valeur située à l'intérieur de "mydata" dans l'objet JSON. Si cet élément n'existe pas, il renverra "N/A" à la place. Si cet élément est trop long pour une chaîne, le système lèvera une exception vers le bloc catch. Nous devons vérifier le nom de cette exception, car si une exception différente s'est produite, il ne serait pas logique d'essayer d'obtenir les données sous forme de flux. Vous pouvez en savoir plus sur la gestion des exceptions ici. Si la valeur est , nous spécifions que nous voulons récupérer mydata sous forme de flux. La récupération des données sous forme de flux renvoie un objet de la classe %Stream.DynamicCharacter. Cela ne déclenche jamais d'exception , mais peut générer une exception si la limite de mémoire du processus est dépassée.

Si vous suivez l'approche décrite ci-dessus, vous ne saurez pas si mydata dans le code est une chaîne ou un flux. Cela signifie que vous devrez suivre le code similaire à celui ci-dessous:

if$ISOBJECT(mydata){
    //Traitement des flux ici
}
else{
    //Traitement des chaînes ici
}

Vous pouvez également utiliser l'option stream chaque fois afin de vous assurer que vous avez toujours un flux à votre disposition. Cependant, cela entraînerait une utilisation inutile des ressources et alourdirait votre code.

Une autre option consiste à ajouter un flux à un objet dynamique à l'aide de %Set. Consultez l'exemple suivant:

set mystream = ##class(%Stream.FileBinary).%New()
do mystream.LinkToFile(“/path/to/your/file”)
do myObj.%Set(“mydata”,mystream,”stream”)

Les données de votre fichier seront désormais enregistrées dans le champ mydata de votre objet dynamique.

%Set et %Get encodent et décodent également les chaînes à l'aide de l'encodage Base64. 

Gardez toujours à l'esprit que l'encodage Base64 est un encodage et non un cryptage ! Il n'y a pas de clés secrètes ni de mots de passe pour décoder votre message, et il est facilement réversible. Par conséquent, vous devez toujours utiliser un protocole crypté, tel que TLS ou HTTPS, pour la transmission ! Base64 est utilisé pour transmettre des caractères non ASCII de manière à ce que les systèmes ASCII puissent les recevoir et les transmettre.

Maintenant que cette remarque importante est faite, nous pouvons enfin voir comment cela fonctionne. Si nous apportons une petite modification à l'exemple de code précédent, le contenu du flux de fichiers sera encodé en Base64.

set mystream = ##class(%Stream.FileBinary).%New()
do mystream.LinkToFile(“/path/to/your/file”)
do myObj.%Set(“mydata”,mystream,”stream>base64”)

D'autre part, si les données du fichier étaient déjà encodées en Base64 et que nous voulions les convertir en données décodées, il suffirait de changer un seul caractère.

set mystream = ##class(%Stream.FileBinary).%New()
do mystream.LinkToFile(“/path/to/your/file”)
do myObj.%Set(“mydata”,mystream,”stream<base64”)

Les signes " supérieur à" ou "inférieur à" indiquent toujours la direction dans laquelle la conversion a lieu. Si nous convertissons un flux non codé en une chaîne Base64, le signe pointera vers Base64. Si nous convertissons un flux codé en Base64 en un flux non codé, le signe pointera de Base64 vers le flux. La même fonctionnalité existe pour les chaînes lorsque string>base64 et string

set something = myObj.%Get(“something”,”NA”,”string>base64”)

Si l'élément "quelque chose" existe, il sera renvoyé sous sa forme encodée en Base64. Cependant, s'il n'existe pas, "NA" sera renvoyé sans être encodé.

Il existe une restriction concernant l'option d'encodage Base64. Seuls les caractères dont le code est compris entre 0 et 255 peuvent être encodés en Base64. Les codes de caractères supérieurs à 255 entraîneront une exception <WIDE CHAR>. FPar exemple, la ligne suivante provoquera une telle exception:

set mychar = $C(256)
do myobj.%Set(“mychar”,mychar,”string>base64”)

Alors, j'ai entendu dire que vous aimiez JSON . . .

Parfois, il y a du JSON à l'intérieur de votre JSON. La manière par défaut de gérer cette situation est généralement celle que vous choisiriez. Cependant, une autre option a été ajoutée à l'argument de type pour traiter un cas d'utilisation différent. Il s'agit du type "json". Regardez l'objet JSON suivant:

{
    “mystring”:”Hello World!”,
    “mynumber”:1234,
    “myjson”:{
        “subitem1”:”Hello Mars!”,
        “subitem2”:”Hello Stars!”
    }
}

En règle générale, lorsque vous rencontrez ce problème, vous devez utiliser la méthode %Get avec la clé « myjson » pour obtenir un objet dynamique. Voici un exemple:

set myjson = myobj.%Get(“myjson”)
write myjson.%Get(“subitem1”)

La ligne ci-dessus écrirait "Hello Mars!". C'est le cas le plus courant dans cette situation. Cependant, dans certains cas, vous préférerez peut-être obtenir le JSON réel contenu dans cet élément sous forme de chaîne. Dans ce cas, vous pouvez procéder comme suit:

set myjson = myobj.%Get(“myjson”,,”json”)
write myjson

La chaîne JSON sera écrite exactement telle qu'elle est:

{“subitem1”:”Hello Mars!”,”subitem2”:”Hello Stars!”}

Cela peut s'avérer utile dans les cas où nous voulons transmettre le JSON tel quel à un autre processus. Notez que, contrairement à tous les autres types nouveaux, celui-ci n'est pris en charge que pour la méthode %Get, et non pour la méthode %Set.

Hourra, hourra, les massives!

Jusqu'à présent, nous avons discuté de ces nouveaux objets dans le contexte de la classe %Library.DynamicObject, mais ils sont également pris en charge pour la classe %Library.DynamicArray. Dans cette classe, %Set et %Get prennent en charge les mêmes arguments de type que dans la classe %Library.DynamicObject. La classe de tableaux dynamiques dispose toutefois d'une méthode %Push supplémentaire. Elle prend en charge les mêmes types que %Set, à l'exception du type JSON.

Sans plus attendre, c'est probablement le bon moment pour revoir vos anciens codes et implémenter ces changements à votre avantage!

0
0 35
Article Iryna Mykhailova · Mai 29, 2025 8m read

J'ai un nouveau projet qui consiste à stocker des informations provenant de réponses REST dans une base de données IRIS. Il me faudra synchroniser les informations provenant d'au moins deux douzaines de points de terminaison REST distincts, ce qui implique la création de presque autant de classes ObjectScript pour stocker les résultats de ces points de terminaison.

Puis-je utiliser ChatGPT pour créer ces classes? La réponse est "Oui", ce qui est génial puisqu'il s'agit de ma première tentative d'utiliser l'IA générative pour quelque chose d'utile. En effet, générer des images de girafes mangeant de la soupe devenait un peu vieux….

Voici ce que j'ai fait:

  • Obtenez un exemple de sortie d'appel REST JSON en utilisant "curl" pour interroger le point de terminaison.
  • Visitez ChatGPT (InterSystems fournit une licence à l'échelle de l'entreprise pour les employés)
  • Accédez au dialogue suivant avec ChatGPT.

J'ai placé la demande suivante dans la fenêtre de message de ChatGPT:

Moi: Générer une classe ObjectScript qui contiendra les données du JSON suivant:

J'ai appuyé sur "Return" avant d'entrer le JSON et ChatGPT m'a donc dirigé comme suit:

ChatGPT: Veuillez fournir la structure JSON pour laquelle vous souhaitez que je génère la classe ObjectScript. Si vous avez un exemple d'objet JSON, collez-le ici et je créerai pour vous la classe ObjectScript InterSystems correspondante.

J'ai saisi ce qui suit dans la fenêtre de message:

{
  "id": 335818632,
  "appId": 113,
  "appName": "Batch",
  "contentId": 182455380233,
  "subject": "Test Subject",
  "name": "Test email campaign name",
  "counters": {
    "processed": 3910,
    "deferred": 86,
    "unsubscribed": 17,
    "statuschange": 17,
    "bounce": 153,
    "mta_dropped": 8,
    "dropped": 299,
    "delivered": 3749,
    "sent": 3903,
    "click": 16,
    "open": 323
  },
  "lastProcessingFinishedAt": 1733232499000,
  "lastProcessingStartedAt": 1733232303000,
  "lastProcessingStateChangeAt": 1733232499000,
  "numIncluded": 4201,
  "processingState": "DONE",
  "scheduledAt": 1733232300000,
  "type": "BATCH_EMAIL"
}

Réponse de ChatGPT:

Voici la classe ObjectScript InterSystems qui correspond à la structure JSON fournie:

Class MyNamespace.MyJSONData Extends (%Persistent, %JSON.Adaptor)
{
Property id As%Integer;Property appId As%Integer;Property appName As%String;Property contentId As%Integer;Property subject As%String;Property name As%String;Property counters As MyNamespace.Counters;Property lastProcessingFinishedAt As%BigInt;Property lastProcessingStartedAt As%BigInt;Property lastProcessingStateChangeAt As%BigInt;Property numIncluded As%Integer;Property processingState As%String;Property scheduledAt As%BigInt;Property type As%String;ClassMethod%OnJSONImport(jsonObject As%Object, instance As MyNamespace.MyJSONData) As%Status
{
    Quit ..%JSONImport(jsonObject, .instance)
}
}

Class MyNamespace.Counters Extends (%SerialObject, %JSON.Adaptor)
{
Property processed As%Integer;Property deferred As%Integer;Property unsubscribed As%Integer;Property statuschange As%Integer;Property bounce As%Integer;Property mta_dropped As%Integer;Property dropped As%Integer;Property delivered As%Integer;Property sent As%Integer;Property click As%Integer;PropertyopenAs%Integer;
}

Avec une explication:

Ce code est un bon départ, mais j'aimerais qu'il s'intègre dans mon paquetage nommé “MyPkg” et que la classe porte le nom “EmaiCampaign”. De plus, grâce à mes connaissances en NI, je sais que les valeurs qui ont généré les propriétés “%BigInt” sont en fait des horaires Linux et que les propriétés devraient être %Library.PosixTime”.

Je fais la demande suivante (je ne sais pas trop pourquoi je dis "s'il vous plaît" à une machine;  je suppose que mes parents ont fait du bon travail):

Moi: Pouvons-nous recréer la classe, s'il vous plaît, en renommant le paquetage " MyPkg" et la classe "EmailCampaign"? De plus, veuillez changer les types de propriétés de %BigInt à %Library.PosixTime.

Reponse de ChatGPT:

Voici la classe ObjectScript mise à jour avec le nom de paquetage et le nom de classe spécifiés, et les propriétés d'horodatage mises à jour pour l'utilisation de %Library.PosixTime:

Class MyPkg.EmailCampaign Extends (%Persistent, %JSON.Adaptor)
{
Property id As%Integer;Property appId As%Integer;Property appName As%String;Property contentId As%Integer;Property subject As%String;Property name As%String;Property counters As MyPkg.Counters;Property lastProcessingFinishedAt As%Library.PosixTime;Property lastProcessingStartedAt As%Library.PosixTime;Property lastProcessingStateChangeAt As%Library.PosixTime;Property numIncluded As%Integer;Property processingState As%String;Property scheduledAt As%Library.PosixTime;Property type As%String;ClassMethod%OnJSONImport(jsonObject As%Object, instance As MyPkg.EmailCampaign) As%Status
{
    Quit ..%JSONImport(jsonObject, .instance)
}
}

Class MyPkg.Counters Extends (%SerialObject, %JSON.Adaptor)
{
Property processed As%Integer;Property deferred As%Integer;Property unsubscribed As%Integer;Property statuschange As%Integer;Property bounce As%Integer;Property mta_dropped As%Integer;Property dropped As%Integer;Property delivered As%Integer;Property sent As%Integer;Property click As%Integer;PropertyopenAs%Integer;
}

Avec une explication suivante:

Après avoir copié le code "tel quel" dans VSCode, des problèmes de syntaxe avec les accolades ont été mis en évidence. Les classes ObjectScript ne permettent pas de définir des classes internes.

Demander à ChatGPT de résoudre le problème des « accolades » en faisant de la classe interne MyPkg.Counters une classe séparée est une opération impossible “no-op”; un humain devra déplacer cette classe dans un autre fichier. ChatGPT a renommé cette classe après la demande suivante:

Moi: La classe telle qu'elle est écrite ne compile pas. Pouvons-nous déplacer la classe interne nommée MyPkg.Counters de la classe principale vers sa propre classe et la renommer en MyPkg.CampaignCounters?

Reponse de ChatGPT:

Voici le code ObjectScript mis à jour avec la classe MyPkg.CampaignCounters déplacée comme sa propre classe:

Class MyPkg.EmailCampaign Extends (%Persistent, %JSON.Adaptor)
{
Property id As%Integer;Property appId As%Integer;Property appName As%String;Property contentId As%Integer;Property subject As%String;Property name As%String;Property counters As MyPkg.CampaignCounters;Property lastProcessingFinishedAt As%Library.PosixTime;Property lastProcessingStartedAt As%Library.PosixTime;Property lastProcessingStateChangeAt As%Library.PosixTime;Property numIncluded As%Integer;Property processingState As%String;Property scheduledAt As%Library.PosixTime;Property type As%String;ClassMethod%OnJSONImport(jsonObject As%Object, instance As MyPkg.EmailCampaign) As%Status
{
    Quit ..%JSONImport(jsonObject, .instance)
}
}

Class MyPkg.CampaignCounters Extends (%SerialObject, %JSON.Adaptor)
{
Property processed As%Integer;Property deferred As%Integer;Property unsubscribed As%Integer;Property statuschange As%Integer;Property bounce As%Integer;Property mta_dropped As%Integer;Property dropped As%Integer;Property delivered As%Integer;Property sent As%Integer;Property click As%Integer;PropertyopenAs%Integer;
}

Après avoir collé ce qui précède dans VSCode et l'avoir compilé, le compilateur a signalé que le type nommé "%Object" n'existe pas dans ObjectScript. v %JSONImport() de %JSON.Adaptor est flexible:

“L'argument d'entrée est soit JSON en tant que chaîne ou flux, soit une sous-classe de %DynamicAbstractObject.

Après avoir supprimé la propriété "As %Object" pour le premier paramètre de %OnJSONImport() dans la première classe et avoir séparé les deux classes dans des fichiers distincts, la classe MyPkg.EmailCampaign s'est compilée avec succès. Cependant, la classe MyPkg.CampaignCounters ne s'est pas compilée ; ChatGPT ne sait pas (pour l'instant ?) que l'underscore est un caractère spécial en ObjectScript (l'opérateur de concaténation de chaînes de caractères).  

Essayons de le lui enseigner.

Moi: Le caractère underscore "_" est un caractère spécial dans ObjectScript. Veuillez changer les propriétés dont le nom contient un underscore en camel case et supprimer l'underscore.

Reponse de ChatGPT:

Voici le code mis à jour avec les propriétés qui avaient des underscores dans leurs noms convertis en camel case:

Class MyPkg.EmailCampaign Extends (%Persistent, %JSON.Adaptor)
{
Property id As%Integer;Property appId As%Integer;Property appName As%String;Property contentId As%Integer;Property subject As%String;Property name As%String;Property counters As MyPkg.CampaignCounters;Property lastProcessingFinishedAt As%Library.PosixTime;Property lastProcessingStartedAt As%Library.PosixTime;Property lastProcessingStateChangeAt As%Library.PosixTime;Property numIncluded As%Integer;Property processingState As%String;Property scheduledAt As%Library.PosixTime;Property type As%String;ClassMethod%OnJSONImport(jsonObject As%Object, instance As MyPkg.EmailCampaign) As%Status
{
    Quit ..%JSONImport(jsonObject, .instance)
}
}

Class MyPkg.CampaignCounters Extends (%SerialObject, %JSON.Adaptor)
{
Property processed As%Integer;Property deferred As%Integer;Property unsubscribed As%Integer;Property statusChange As%Integer;Property bounce As%Integer;Property mtaDropped As%Integer;Property dropped As%Integer;Property delivered As%Integer;Property sent As%Integer;Property click As%Integer;PropertyopenAs%Integer;
}

Avec une explication suivante:

ChatGPT s'est surpassé et a changé une autre propriété, nommée avec deux mots distincts, en camel case également (statuschange); je garde ce changement puisque d'autres propriétés nommées de la même manière dans la classe principale sont toutes en camel case.

Avec le dernier code généré dans deux fichiers séparés (et en supprimant la définition "As %Object" dans la définition de la méthode %OnJSONImport()), tout le code se compile avec succès.

Ces classes générées sont un excellent point de départ pour ce dont j'ai besoin et je répéterai le processus pour les autres sources de données REST de ce projet, ce qui me permettra d'éviter de nombreuses saisies inutiles.

0
0 27
Article Lorenzo Scalese · Mai 7, 2025 6m read

Introduction

À mesure que l'automatisation pilotée par l'IA devient un élément essentiel des systèmes d'information modernes, l'intégration des capacités d'IA dans les plateformes existantes doit être transparente et efficace. Le projet IRIS Agent montre comment l'IA générative peut fonctionner sans effort avec InterSystems IRIS, grâce à son puissant cadre d'interopérabilité, sans qu'il soit nécessaire d'apprendre Python ou de créer des workflows d'IA distincts à partir de zéro.
Ce projet examine la manière dont ChatGPT et Anthropic Claude, deux modèles d'IA parmi les plus avancés, peuvent interagir avec IRIS à l'aide de GPT personnalisés et du protocole MCP (Model Context Protocol). Plutôt que de créer des pipelines d'IA isolés, IRIS Agent traite l'IA comme un service d'interopérabilité, permettant ainsi aux organisations d'améliorer l'automatisation, la prise de décision et le traitement des données sans perturber leur architecture existante.
En s'appuyant sur des outils d'interopérabilité natifs d'IRIS, les développeurs peuvent intégrer des modèles d'IA de manière transparente, comme n'importe quel autre composant du système. Cette approche garantit la stabilité, la sécurité, l'évolutivité et l'auditabilité, tout en permettant une interaction en langage naturel, la récupération de données en temps réel et l'administration automatisée du système, le tout dans l'environnement familier d'IRIS.

Technologies sous-jacentes à IRIS Agent

Le projet IRIS Agent s'appuie sur un ensemble de technologies puissantes pour garantir efficacité, évolutivité et intégration transparente:

  • InterSystems IRIS – Une plateforme robuste dédiée au développement d'applications et à l'intégration de données, qui utilise ObjectScript pour le code côté serveur.
  • Custom GPT Bot – Un assistant IA personnalisé conçu pour rationaliser les interactions avec le système, basé sur ChatGPT.
  • Claude AI Desktop – Facilite la communication avec le serveur via le protocole MCP (Model Context Protocol).
  • Node.js – Gère les communications avec le serveur MCP
  • OpenAPI – Documentation API standardisée.
  • Docker – Compartimente l'application pour simplifier le déploiement et la gestion des dépendances.

Présentation interne

Voici à quoi ressemble notre projet sous le capot IRIS:

La Production comprend les éléments suivants:

  • LanguageModelIn: un service qui reçoit une requête API et la redirige vers l'opération responsable.
  • Meds: une opération qui recherche des médicaments sur une API tierce.
  • Metrics: une opération qui recherche des informations OPS telles que les journaux, les erreurs et les messages dans le système Iris.
  • Namespaces: une opération qui répertorie, recherche et modifie les espaces de noms dans le système Iris.
  • Users: une opération qui répertorie, recherche, crée et supprime des utilisateurs dans le système Iris.

Le fonctionnement du service est particulièrement visible dans l'afficheur de messages et les traces. Il peut nous aider à suivre les opérations et à diagnostiquer les problèmes, par exemple les requêtes:

…et les réponses:


L'un des points forts de ce projet réside dans le fait que le service LanguageModelIn génère automatiquement une documentation API ouverte pour les opérations métier dans le cadre de la production IRIS Interoperability. Cette API  nous permet de connecter facilement les GPT personnalisés à ChatGPT et au serveur MCP (Model Context Protocol) à Claude AI Desktop. 

Intégration avec ChatGPT 

Après avoir terminé tous les processus d'installation et de configuration, que vous trouverez dans notre fichier ReadMe, ReadMe, demandons à notre agent IRIS GPT d'OpenAI quelles sont ses fonctionnalités actuelles:

  

Et créez un nouvel utilisateur…

   


Vérification des mises à jour...

   

Intégration avec des Sources de données externes

L'une des fonctionnalités remarquables de l'agent IRIS est sa capacité à interroger de manière transparente non seulement les données stockées dans la base de données InterSystems IRIS, mais également des sources de données externes. Dans notre exemple, l'agent s'intègre à l'OpenFDA API pour fournir des informations en temps réel sur les médicaments. Cela permet aux utilisateurs de rechercher des informations sur les médicaments, des rapports de sécurité et des données de conformité réglementaire directement dans le système. 
Dans notre projet, l'API offre la possibilité de rechercher des médicaments par leur nom. Recherchons donc les médicaments dont le nom contient le mot "flu".

   

Si vous souhaitez l'essayer dès maintenant, suivez le lien et engagez une conversation avec notre IRIS Agent démo.

Intégration avec Claude AI Desktop

L'une des fonctionnalités clés de l'agent IRIS est sa capacité à interagir avec Claude AI Desktop, un assistant IA local développé par Anthropic. L'intégration est assurée par le protocole MCP (Model Context Protocol), qui facilite la communication entre Claude et les applications externes. Pour ce faire, l'agent IRIS utilise un serveur MCP Node.js dédié qui sert d'intermédiaire, traitant les requêtes entrantes et les acheminant entre Claude et le système IRIS.
Cette configuration permet aux utilisateurs d'interagir directement avec l'agent IRIS via l'interface Claude, en émettant des commandes en langage naturel pour récupérer des données système, gérer les configurations et exécuter des tâches administratives. Le serveur MCP garantit un échange de données fluide, tout en maintenant l'efficacité et la sécurité, et fournit aux administrateurs un assistant puissant basé sur l'IA pour la gestion du système.

         

Conclusion

Le projet IRIS Agent présente le potentiel de l'automatisation pilotée par l'IA dans les environnements d'entreprise modernes. En intégrant de manière transparente InterSystems IRIS, Claude AI et Custom GPT, il simplifie la gestion des systèmes, améliore l'efficacité et ouvre la voie à de futures innovations. Notre projet démontre également que vous êtes déjà prêt pour la révolution de l'IA avec InterSystems IRIS!


Si vous avez apprécié la découverte d'IRIS Agent et de ses fonctionnalités et que vous souhaitez nous soutenir, veuillez prendre quelques instants pour voter pour notre application ici https://openexchange.intersystems.com/contest/40. Je vous remercie!


Développeurs de projet:

Banksia Global est une société de conseil technologique de premier plan qui aide les organisations à exploiter pleinement le potentiel des solutions modernes de gestion des données. En mettant l'accent sur la plateforme InterSystems IRIS, Banksia Global fournit des conseils stratégiques, des services d'intégration de systèmes et de développement de logiciels personnalisés à des clients issus de divers secteurs. Son expertise réside dans la fourniture de solutions hautement performantes et évolutives qui permettent aux entreprises de stimuler l'innovation, de rationaliser leurs opérations et de saisir de nouvelles opportunités. Réputée pour son approche collaborative et agile, Banksia Global travaille en étroite collaboration avec ses clients afin de s'assurer que chaque solution est adaptée à leurs besoins spécifiques, favorisant ainsi des partenariats à long terme et une croissance durable.

0
0 59
Article Sylvain Guilbaud · Mars 28, 2025 54m read

Depuis l'introduction d'Embedded Python, il y a toujours eu un doute sur ses performances par rapport à ObjectScript et J'en ai discuté à plusieurs reprises avec @Guillaume Rongier , eh bien, profitant du fait que je faisais une petite application pour capturer les données des concours publics en Espagne et pouvoir effectuer des recherches en utilisant les capacités de VectorSearch, j'ai vu l'opportunité de réaliser un petit test.

Données pour le test

Les informations relatives aux concours publics sont fournies mensuellement dans des fichiers XML à partir de cette URL  et le format typique des informations d'un concours est le suivant:

 
Spoiler
<entry>
        <id>https://contrataciondelestado.es/sindicacion/licitacionesPerfilContratante/15070121</id>
        <link href="https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&amp;idEvl=zVQ4gDdr3Y436J9Lctlsuw%3D%3D"/>
        <summary type="text">Id licitación: C54243062800; Órgano de Contratación: Dirección General de Carreteras; Importe: 3088367.31 EUR; Estado: RES</summary>
        <title>39-MU-6280; 54.408/24. Actuaciones para el desarrollo del plan de acción contra el ruido de la Fase II en la Región de Murcia. Plan de Recuperación, Transformación y Resiliencia, Next Generation EU.</title>
        <updated>2024-12-19T07:58:39.502+01:00</updated>
        <cac-place-ext:ContractFolderStatus>
            <cbc:ContractFolderID>C54243062800</cbc:ContractFolderID>
            <cbc-place-ext:ContractFolderStatusCode listURI="https://contrataciondelestado.es/codice/cl/2.04/SyndicationContractFolderStatusCode-2.04.gc" languageID="es">RES</cbc-place-ext:ContractFolderStatusCode>
            <cac-place-ext:LocatedContractingParty>
                <cbc:ContractingPartyTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.10/ContractingAuthorityCode-2.10.gc">1</cbc:ContractingPartyTypeCode>
                <cbc:ActivityCode listURI="http://contrataciondelestado.es/codice/cl/2.10/ContractingAuthorityActivityCode-2.10.gc">1</cbc:ActivityCode>
                <cbc:BuyerProfileURIID>https://contrataciondelestado.es/wps/poc?uri=deeplink:perfilContratante&amp;idBp=bbqeQ9uN6YE%3D</cbc:BuyerProfileURIID>
                <cac:Party>
                    <cbc:WebsiteURI>http://www.fomento.es</cbc:WebsiteURI>
                    <cac:PartyIdentification>
                        <cbc:ID schemeName="DIR3">E00124905</cbc:ID>
                    </cac:PartyIdentification>
                    <cac:PartyIdentification>
                        <cbc:ID schemeName="NIF">S2817015G</cbc:ID>
                    </cac:PartyIdentification>
                    <cac:PartyIdentification>
                        <cbc:ID schemeName="ID_PLATAFORMA">10000170000108</cbc:ID>
                    </cac:PartyIdentification>
                    <cac:PartyName>
                        <cbc:Name>Dirección General de Carreteras</cbc:Name>
                    </cac:PartyName>
                    <cac:PostalAddress>
                        <cbc:CityName>Madrid</cbc:CityName>
                        <cbc:PostalZone>28071</cbc:PostalZone>
                        <cac:AddressLine>
                            <cbc:Line>Paseo de la Castellana 67 - Despacho B750</cbc:Line>
                        </cac:AddressLine>
                        <cac:Country>
                            <cbc:IdentificationCode listURI="http://contrataciondelestado.es/codice/cl/2.08/CountryIdentificationCode-2.08.gc">ES</cbc:IdentificationCode>
                            <cbc:Name>España</cbc:Name>
                        </cac:Country>
                    </cac:PostalAddress>
                    <cac:Contact>
                        <cbc:Name>Dirección General de Carreteras</cbc:Name>
                        <cbc:Telephone>915978341</cbc:Telephone>
                        <cbc:Telefax>915978547</cbc:Telefax>
                        <cbc:ElectronicMail>dgc.licitaciones@fomento.es</cbc:ElectronicMail>
                    </cac:Contact>
                </cac:Party>
                <cac-place-ext:ParentLocatedParty>
                    <cac:PartyName>
                        <cbc:Name>Dirección General de Carreteras</cbc:Name>
                    </cac:PartyName>
                    <cac-place-ext:ParentLocatedParty>
                        <cac:PartyName>
                            <cbc:Name>Secretaría General de Transporte Terrestre</cbc:Name>
                        </cac:PartyName>
                        <cac-place-ext:ParentLocatedParty>
                            <cac:PartyName>
<cbc:Name>Secretaría de Estado de Transportes y Movilidad Sostenible</cbc:Name>
                            </cac:PartyName>
                            <cac-place-ext:ParentLocatedParty>
<cac:PartyIdentification>
    <cbc:ID schemeName="DIR3">E05229701</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
    <cbc:Name>Ministerio de Transportes y Movilidad Sostenible</cbc:Name>
</cac:PartyName>
<cac-place-ext:ParentLocatedParty>
    <cac:PartyIdentification>
        <cbc:ID schemeName="DIR3">EA9999999</cbc:ID>
    </cac:PartyIdentification>
    <cac:PartyName>
        <cbc:Name>ADMINISTRACIÓN GENERAL DEL ESTADO</cbc:Name>
    </cac:PartyName>
    <cac-place-ext:ParentLocatedParty>
        <cac:PartyName>
            <cbc:Name>Sector Público</cbc:Name>
        </cac:PartyName>
    </cac-place-ext:ParentLocatedParty>
</cac-place-ext:ParentLocatedParty>
                            </cac-place-ext:ParentLocatedParty>
                        </cac-place-ext:ParentLocatedParty>
                    </cac-place-ext:ParentLocatedParty>
                </cac-place-ext:ParentLocatedParty>
            </cac-place-ext:LocatedContractingParty>
            <cac:ProcurementProject>
                <cbc:Name>39-MU-6280; 54.408/24. Actuaciones para el desarrollo del plan de acción contra el ruido de la Fase II en la Región de Murcia. Plan de Recuperación, Transformación y Resiliencia, Next Generation EU.</cbc:Name>
                <cbc:TypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/ContractCode-2.08.gc">3</cbc:TypeCode>
                <cbc:SubTypeCode listURI="http://contrataciondelestado.es/codice/cl/1.04/WorksContractCode-1.04.gc">4500</cbc:SubTypeCode>
                <cbc:MixContractIndicator>false</cbc:MixContractIndicator>
                <cac:BudgetAmount>
                    <cbc:EstimatedOverallContractAmount currencyID="EUR">3706040.77</cbc:EstimatedOverallContractAmount>
                    <cbc:TotalAmount currencyID="EUR">3736924.45</cbc:TotalAmount>
                    <cbc:TaxExclusiveAmount currencyID="EUR">3088367.31</cbc:TaxExclusiveAmount>
                </cac:BudgetAmount>
                <cac:RequiredCommodityClassification>
                    <cbc:ItemClassificationCode listURI="http://contrataciondelestado.es/codice/cl/2.04/CPV2008-2.04.gc">45233000</cbc:ItemClassificationCode>
                </cac:RequiredCommodityClassification>
                <cac:RealizedLocation>
                    <cbc:CountrySubentity>Región de Murcia</cbc:CountrySubentity>
                    <cbc:CountrySubentityCode listURI="http://contrataciondelestado.es/codice/cl/2.08/NUTS-2021.gc">ES62</cbc:CountrySubentityCode>
                    <cac:Address>
                        <cac:Country>
                            <cbc:IdentificationCode listURI="http://contrataciondelestado.es/codice/cl/2.08/CountryIdentificationCode-2.08.gc">ES</cbc:IdentificationCode>
                            <cbc:Name>España</cbc:Name>
                        </cac:Country>
                    </cac:Address>
                </cac:RealizedLocation>
                <cac:PlannedPeriod>
                    <cbc:DurationMeasure unitCode="MON">6</cbc:DurationMeasure>
                </cac:PlannedPeriod>
            </cac:ProcurementProject>
            <cac:TenderResult>
                <cbc:ResultCode listURI="http://contrataciondelestado.es/codice/cl/2.09/TenderResultCode-2.09.gc">9</cbc:ResultCode>
                <cbc:Description>Por ser la ofertas más ventajosa</cbc:Description>
                <cbc:AwardDate>2024-11-26</cbc:AwardDate>
                <cbc:ReceivedTenderQuantity>20</cbc:ReceivedTenderQuantity>
                <cbc:LowerTenderAmount currencyID="EUR">2388215.74</cbc:LowerTenderAmount>
                <cbc:HigherTenderAmount currencyID="EUR">2764090</cbc:HigherTenderAmount>
                <cbc:SMEsReceivedTenderQuantity>6</cbc:SMEsReceivedTenderQuantity>
                <cbc:SMEAwardedIndicator>false</cbc:SMEAwardedIndicator>
                <cac:Contract>
                    <cbc:IssueDate>2024-12-18</cbc:IssueDate>
                </cac:Contract>
                <cac:WinningParty>
                    <cac:PartyIdentification>
                        <cbc:ID schemeName="NIF">A17013863</cbc:ID>
                    </cac:PartyIdentification>
                    <cac:PartyName>
                        <cbc:Name>CONSTRUCCIONES RUBAU, S.A.</cbc:Name>
                    </cac:PartyName>
                    <cac:PhysicalLocation>
                        <cac:Address>
                            <cbc:CityName>Madrid</cbc:CityName>
                            <cbc:PostalZone>28046</cbc:PostalZone>
                            <cac:Country>
<cbc:IdentificationCode listURI="http://contrataciondelestado.es/codice/cl/2.08/CountryIdentificationCode-2.08.gc" name="España">ES</cbc:IdentificationCode>
                            </cac:Country>
                        </cac:Address>
                    </cac:PhysicalLocation>
                </cac:WinningParty>
                <cac:AwardedTenderedProject>
                    <cac:LegalMonetaryTotal>
                        <cbc:TaxExclusiveAmount currencyID="EUR">2469149.66</cbc:TaxExclusiveAmount>
                        <cbc:PayableAmount currencyID="EUR">2987671.09</cbc:PayableAmount>
                    </cac:LegalMonetaryTotal>
                </cac:AwardedTenderedProject>
            </cac:TenderResult>
            <cac:TenderingTerms>
                <cbc:RequiredCurriculaIndicator>false</cbc:RequiredCurriculaIndicator>
                <cbc:VariantConstraintIndicator>false</cbc:VariantConstraintIndicator>
                <cbc:FundingProgramCode listURI="http://contrataciondelestado.es/codice/cl/2.08/FundingProgramCode-2.08.gc" name="Financiación con fondos de la UE">EU</cbc:FundingProgramCode>
                <cbc:FundingProgramCode listURI="http://contrataciondelestado.es/codice/cl/2.08/FundingProgramCode-2.08.gc" name="Asociado al Plan de Recuperación, Transformación y Resiliencia">PRTR</cbc:FundingProgramCode>
                <cbc:FundingProgram>NEXT GENERATION EU</cbc:FundingProgram>
                <cbc:ProcurementNationalLegislationCode listURI="https://contrataciondelestado.es/codice/cl/2.08/ProcurementNationalLegislationCode-2.08.gc">3</cbc:ProcurementNationalLegislationCode>
                <cbc:ReceivedAppealQuantity>0</cbc:ReceivedAppealQuantity>
                <cac:RequiredFinancialGuarantee>
                    <cbc:GuaranteeTypeCode listURI="http://contrataciondelestado.es/codice/cl/1.04/GuaranteeTypeCode-1.04.gc">3</cbc:GuaranteeTypeCode>
                    <cbc:AmountRate>5</cbc:AmountRate>
                </cac:RequiredFinancialGuarantee>
                <cac:RequiredFinancialGuarantee>
                    <cbc:GuaranteeTypeCode listURI="http://contrataciondelestado.es/codice/cl/1.04/GuaranteeTypeCode-1.04.gc">2</cbc:GuaranteeTypeCode>
                    <cbc:AmountRate>5</cbc:AmountRate>
                </cac:RequiredFinancialGuarantee>
                <cac:ProcurementLegislationDocumentReference>
                    <cbc:ID>N/A</cbc:ID>
                </cac:ProcurementLegislationDocumentReference>
                <cac:TendererQualificationRequest>
                    <cac:RequiredBusinessClassificationScheme>
                        <cbc:ID>RequiredBusinessProfileCode</cbc:ID>
                        <cac:ClassificationCategory>
                            <cbc:CodeValue>G6-5</cbc:CodeValue>
                        </cac:ClassificationCategory>
                    </cac:RequiredBusinessClassificationScheme>
                    <cac:FinancialEvaluationCriteria>
                        <cbc:EvaluationCriteriaTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.0/FinancialCapabilityTypeCode-2.0.gc">ZZZ</cbc:EvaluationCriteriaTypeCode>
                        <cbc:Description>Se acreditará con la clasificación</cbc:Description>
                    </cac:FinancialEvaluationCriteria>
                    <cac:SpecificTendererRequirement>
                        <cbc:RequirementTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/DeclarationTypeCode-2.08.gc">1</cbc:RequirementTypeCode>
                        <cbc:Description>Capacidad de obrar</cbc:Description>
                    </cac:SpecificTendererRequirement>
                </cac:TendererQualificationRequest>
                <cac:AwardingTerms>
                    <cac:AwardingCriteria>
                        <cbc:AwardingCriteriaTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.0/AwardingCriteriaCode-2.0.gc">SUBJ</cbc:AwardingCriteriaTypeCode>
                        <cbc:Description>Juicio de valor</cbc:Description>
                        <cbc:Note>Criterios evaluables mediante juicio de valor.</cbc:Note>
                        <cbc:AwardingCriteriaSubTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.09/AwardingCriteriaNotAutomaticallyEvaluatedSubTypeCode-2.09.gc">99</cbc:AwardingCriteriaSubTypeCode>
                        <cbc:WeightNumeric>49</cbc:WeightNumeric>
                    </cac:AwardingCriteria>
                    <cac:AwardingCriteria>
                        <cbc:AwardingCriteriaTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.0/AwardingCriteriaCode-2.0.gc">OBJ</cbc:AwardingCriteriaTypeCode>
                        <cbc:Description>Precio</cbc:Description>
                        <cbc:AwardingCriteriaSubTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.09/AwardingCriteriaAutomaticallyEvaluatedSubTypeCode-2.09.gc">1</cbc:AwardingCriteriaSubTypeCode>
                        <cbc:WeightNumeric>45.9</cbc:WeightNumeric>
                    </cac:AwardingCriteria>
                    <cac:AwardingCriteria>
                        <cbc:AwardingCriteriaTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.0/AwardingCriteriaCode-2.0.gc">OBJ</cbc:AwardingCriteriaTypeCode>
                        <cbc:Description>Incremento de gastos de ensayos</cbc:Description>
                        <cbc:Note>El licitador deberá consignar el porcentaje total de gastos de ensayo al que se compromete</cbc:Note>
                        <cbc:AwardingCriteriaSubTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.09/AwardingCriteriaAutomaticallyEvaluatedSubTypeCode-2.09.gc">2</cbc:AwardingCriteriaSubTypeCode>
                        <cbc:WeightNumeric>5.1</cbc:WeightNumeric>
                    </cac:AwardingCriteria>
                </cac:AwardingTerms>
                <cac:TenderRecipientParty>
                    <cbc:EndpointID>https://contrataciondelestado.es</cbc:EndpointID>
                </cac:TenderRecipientParty>
                <cac:Language>
                    <cbc:ID>es</cbc:ID>
                </cac:Language>
            </cac:TenderingTerms>
            <cac:TenderingProcess>
                <cbc:ProcedureCode listURI="https://contrataciondelestado.es/codice/cl/2.07/SyndicationTenderingProcessCode-2.07.gc">1</cbc:ProcedureCode>
                <cbc:UrgencyCode listURI="http://contrataciondelestado.es/codice/cl/1.04/DiligenceTypeCode-1.04.gc">1</cbc:UrgencyCode>
                <cbc:ContractingSystemCode listURI="http://contrataciondelestado.es/codice/cl/2.08/ContractingSystemTypeCode-2.08.gc">0</cbc:ContractingSystemCode>
                <cbc:SubmissionMethodCode listURI="http://contrataciondelestado.es/codice/cl/1.04/TenderDeliveryCode-1.04.gc">1</cbc:SubmissionMethodCode>
                <cbc:OverThresholdIndicator>false</cbc:OverThresholdIndicator>
                <cac:DocumentAvailabilityPeriod>
                    <cbc:EndDate>2024-07-11</cbc:EndDate>
                    <cbc:EndTime>19:00:00</cbc:EndTime>
                </cac:DocumentAvailabilityPeriod>
                <cac:TenderSubmissionDeadlinePeriod>
                    <cbc:EndDate>2024-07-11</cbc:EndDate>
                    <cbc:EndTime>19:00:00</cbc:EndTime>
                </cac:TenderSubmissionDeadlinePeriod>
                <cac:AuctionTerms>
                    <cbc:AuctionConstraintIndicator>false</cbc:AuctionConstraintIndicator>
                </cac:AuctionTerms>
            </cac:TenderingProcess>
            <cac:LegalDocumentReference>
                <cbc:ID>10 39-MU-6280_PCAP1 COMPLETO.pdf</cbc:ID>
                <cac:Attachment>
                    <cac:ExternalReference>
                        <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=e5192f55-437c-4336-bcae-fa5ed89ed137</cbc:URI>
                        <cbc:DocumentHash>TaNyzb5w+ClWd4GazjY4A6j0n90=</cbc:DocumentHash>
                    </cac:ExternalReference>
                </cac:Attachment>
            </cac:LegalDocumentReference>
            <cac:TechnicalDocumentReference>
                <cbc:ID>13 39-MU-6280 ENLACES PROYECTO.pdf</cbc:ID>
                <cac:Attachment>
                    <cac:ExternalReference>
                        <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=5f34283e-8f1f-4111-83bc-6ee7c627f85a</cbc:URI>
                        <cbc:DocumentHash>C+IvGwHro7JPdvGq0G0Zw5qd4jQ=</cbc:DocumentHash>
                    </cac:ExternalReference>
                </cac:Attachment>
            </cac:TechnicalDocumentReference>
            <cac:AdditionalDocumentReference>
                <cbc:ID>39-MU-6280.xml</cbc:ID>
                <cac:Attachment>
                    <cac:ExternalReference>
                        <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=f0de9e5c-3148-464a-9d1d-6755d7ce3e97</cbc:URI>
                        <cbc:DocumentHash>Mo8VWVuBQYTANqJQ8I2ydW6lmkM=</cbc:DocumentHash>
                    </cac:ExternalReference>
                </cac:Attachment>
            </cac:AdditionalDocumentReference>
            <cac:AdditionalDocumentReference>
                <cbc:ID>Instrucciones DEUC.pdf</cbc:ID>
                <cac:Attachment>
                    <cac:ExternalReference>
                        <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=f8ffa4b2-7c67-41f4-ad8c-490a1cd924e4</cbc:URI>
                        <cbc:DocumentHash>2XK7llhvbjvUXAN8KlDbZhtleg8=</cbc:DocumentHash>
                    </cac:ExternalReference>
                </cac:Attachment>
            </cac:AdditionalDocumentReference>
            <cac:AdditionalDocumentReference>
                <cbc:ID>39-MU-6280.pdf</cbc:ID>
                <cac:Attachment>
                    <cac:ExternalReference>
                        <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=d52c9815-e054-4aea-aed0-b0a43a9c77d5</cbc:URI>
                        <cbc:DocumentHash>B7+m/6Aq3+UHDBARLcj9tZQJivo=</cbc:DocumentHash>
                    </cac:ExternalReference>
                </cac:Attachment>
            </cac:AdditionalDocumentReference>
            <cac-place-ext:ValidNoticeInfo>
                <cbc-place-ext:NoticeTypeCode listURI="https://contrataciondelestado.es/codice/cl/2.11/TenderingNoticeTypeCode-2.11.gc">DOC_CN</cbc-place-ext:NoticeTypeCode>
                <cac-place-ext:AdditionalPublicationStatus>
                    <cbc-place-ext:PublicationMediaName>BOE</cbc-place-ext:PublicationMediaName>
                    <cac-place-ext:AdditionalPublicationDocumentReference>
                        <cbc:IssueDate>2024-06-13</cbc:IssueDate>
                    </cac-place-ext:AdditionalPublicationDocumentReference>
                </cac-place-ext:AdditionalPublicationStatus>
            </cac-place-ext:ValidNoticeInfo>
            <cac-place-ext:ValidNoticeInfo>
                <cbc-place-ext:NoticeTypeCode listURI="https://contrataciondelestado.es/codice/cl/2.11/TenderingNoticeTypeCode-2.11.gc">DOC_CAN_ADJ</cbc-place-ext:NoticeTypeCode>
                <cac-place-ext:AdditionalPublicationStatus>
                    <cbc-place-ext:PublicationMediaName>Perfil del contratante</cbc-place-ext:PublicationMediaName>
                    <cac-place-ext:AdditionalPublicationDocumentReference>
                        <cbc:IssueDate>2024-11-27</cbc:IssueDate>
                    </cac-place-ext:AdditionalPublicationDocumentReference>
                </cac-place-ext:AdditionalPublicationStatus>
            </cac-place-ext:ValidNoticeInfo>
            <cac-place-ext:ValidNoticeInfo>
                <cbc-place-ext:NoticeTypeCode listURI="https://contrataciondelestado.es/codice/cl/2.11/TenderingNoticeTypeCode-2.11.gc">DOC_CD</cbc-place-ext:NoticeTypeCode>
                <cac-place-ext:AdditionalPublicationStatus>
                    <cbc-place-ext:PublicationMediaName>Perfil del contratante</cbc-place-ext:PublicationMediaName>
                    <cac-place-ext:AdditionalPublicationDocumentReference>
                        <cbc:IssueDate>2024-06-06</cbc:IssueDate>
                    </cac-place-ext:AdditionalPublicationDocumentReference>
                </cac-place-ext:AdditionalPublicationStatus>
            </cac-place-ext:ValidNoticeInfo>
            <cac-place-ext:ValidNoticeInfo>
                <cbc-place-ext:NoticeTypeCode listURI="https://contrataciondelestado.es/codice/cl/2.11/TenderingNoticeTypeCode-2.11.gc">DOC_CN</cbc-place-ext:NoticeTypeCode>
                <cac-place-ext:AdditionalPublicationStatus>
                    <cbc-place-ext:PublicationMediaName>Perfil del contratante</cbc-place-ext:PublicationMediaName>
                    <cac-place-ext:AdditionalPublicationDocumentReference>
                        <cbc:IssueDate>2024-06-06</cbc:IssueDate>
                    </cac-place-ext:AdditionalPublicationDocumentReference>
                </cac-place-ext:AdditionalPublicationStatus>
            </cac-place-ext:ValidNoticeInfo>
            <cac-place-ext:ValidNoticeInfo>
                <cbc-place-ext:NoticeTypeCode listURI="https://contrataciondelestado.es/codice/cl/2.11/TenderingNoticeTypeCode-2.11.gc">DOC_FORM</cbc-place-ext:NoticeTypeCode>
                <cac-place-ext:AdditionalPublicationStatus>
                    <cbc-place-ext:PublicationMediaName>Perfil del contratante</cbc-place-ext:PublicationMediaName>
                    <cac-place-ext:AdditionalPublicationDocumentReference>
                        <cbc:IssueDate>2024-12-19</cbc:IssueDate>
                    </cac-place-ext:AdditionalPublicationDocumentReference>
                </cac-place-ext:AdditionalPublicationStatus>
            </cac-place-ext:ValidNoticeInfo>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-808fc79b-06f9-4f36-9949-667977a5f86d</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">14</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-808fc79b-06f9-4f36-9949-667977a5f86d</cbc:URI>
                            <cbc:FileName>Informe sobre las ofertas incursas en presunción de anormalidad</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-715e4b11-0c10-44d2-9127-81a56418ae13</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">12</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-715e4b11-0c10-44d2-9127-81a56418ae13</cbc:URI>
                            <cbc:FileName>Acta del órgano de asistencia</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-f761442b-7a0c-44b8-9bd5-7c09187c8ebe</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">1</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-f761442b-7a0c-44b8-9bd5-7c09187c8ebe</cbc:URI>
                            <cbc:FileName>Actos públicos informativos o de aperturas de ofertas</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-526c90fa-93d8-4db8-8feb-dc96d6a5bfce</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">12</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-526c90fa-93d8-4db8-8feb-dc96d6a5bfce</cbc:URI>
                            <cbc:FileName>Acta del órgano de asistencia</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-1a70d65c-0e41-4302-a9be-4a39a072903e</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">12</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-1a70d65c-0e41-4302-a9be-4a39a072903e</cbc:URI>
                            <cbc:FileName>Acta del órgano de asistencia</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-84248c0b-2d31-4307-9e10-0642ab0ac3aa</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">12</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-84248c0b-2d31-4307-9e10-0642ab0ac3aa</cbc:URI>
                            <cbc:FileName>Acta del órgano de asistencia</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-476ebe20-72eb-479e-9815-05fc29efd728</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">12</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-476ebe20-72eb-479e-9815-05fc29efd728</cbc:URI>
                            <cbc:FileName>Acta del órgano de asistencia</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-96d6f24e-8931-47c4-9feb-a87ed7bddcbe</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">13</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-96d6f24e-8931-47c4-9feb-a87ed7bddcbe</cbc:URI>
                            <cbc:FileName>Informe de valoración de los criterios de adjudicación cuantificables mediante juicio de valor</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>2024-3f052589-4887-46d8-9a0a-f821ced98d8a</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">1</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=2024-3f052589-4887-46d8-9a0a-f821ced98d8a</cbc:URI>
                            <cbc:FileName>Actos públicos informativos o de aperturas de ofertas</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>f8896783-0abc-48ab-87c1-cf1f5cd7e367</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">11</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=f8896783-0abc-48ab-87c1-cf1f5cd7e367</cbc:URI>
                            <cbc:FileName>Documento de aprobación del expediente</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>d93158fa-158c-4ddf-a037-ea8ae1372ddb</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">8</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=d93158fa-158c-4ddf-a037-ea8ae1372ddb</cbc:URI>
                            <cbc:FileName>Acuerdo de iniciación del expediente</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
            <cac-place-ext:GeneralDocument>
                <cac-place-ext:GeneralDocumentDocumentReference>
                    <cbc:ID>daffb941-c1b3-415a-950a-bcf2c51f13fa</cbc:ID>
                    <cbc:DocumentTypeCode listURI="http://contrataciondelestado.es/codice/cl/2.08/GeneralContractDocuments-2.08.gc">ZZZ</cbc:DocumentTypeCode>
                    <cac:Attachment>
                        <cac:ExternalReference>
                            <cbc:URI>https://contrataciondelestado.es/wps/wcm/connect/PLACE_es/Site/area/docAccCmpnt?srv=cmpnt&amp;cmpntname=GetDocumentsById&amp;source=library&amp;DocumentIdParam=daffb941-c1b3-415a-950a-bcf2c51f13fa</cbc:URI>
                            <cbc:FileName>Enlace nuevo a proyecto</cbc:FileName>
                        </cac:ExternalReference>
                    </cac:Attachment>
                </cac-place-ext:GeneralDocumentDocumentReference>
            </cac-place-ext:GeneralDocument>
        </cac-place-ext:ContractFolderStatus>
    </entry>
 

Comme vous le voyez, chaque concours a des dimensions considérables et dans chaque fichier, nous pouvons trouver environ 450 concours. Cette dimension ne permet pas d'utiliser une classe d'ObjectScript pour le mappage (on pourrait... mais je ne suis pas prêt à le faire).  

Codes pour les tests

Mon idée est de capturer uniquement les champs pertinents pour les recherches ultérieures. Pour ce faire, j'ai créé la classe suivante qui nous servira à stocker les informations capturées:

Class Inquisidor.Object.Licitacion Extends (%Persistent, %XML.Adaptor) [ DdlAllowed ]
{

Property IdLicitacion As%String(MAXLEN = 200);Property Titulo As%String(MAXLEN = 2000);Property URL As%String(MAXLEN = 1000);Property Resumen As%String(MAXLEN = 2000);Property TituloVectorizado As%Vector(DATATYPE = "DECIMAL", LEN = 384);Property Contratante As%String(MAXLEN = 2000);Property URLContratante As%String(MAXLEN = 2000);Property ValorEstimado As%Numeric(STORAGEDEFAULT = "columnar");Property ImporteTotal As%Numeric(STORAGEDEFAULT = "columnar");Property ImporteTotalSinImpuestos As%Numeric(STORAGEDEFAULT = "columnar");Property FechaAdjudicacion As%Date;Property Estado As%String;Property Ganador As%String(MAXLEN = 200);Property ImporteGanador As%Numeric(STORAGEDEFAULT = "columnar");Property ImporteGanadorSinImpuestos As%Numeric(STORAGEDEFAULT = "columnar");Property Clasificacion As%String(MAXLEN = 10);Property Localizacion As%String(MAXLEN = 200); Index IndexContratante On Contratante; Index IndexGanador On Ganador; Index IndexClasificacion On Clasificacion; Index IndexLocalizacion On Localizacion; Index IndexIdLicitation On IdLicitacion [ PrimaryKey ]; }

Pour capturer les données à l'aide d'Embedded Python, j'ai utilisé la bibliothèque  xml.etree.ElementTree  qui nous permet d'extraire les valeurs nœud par nœud. Voici la méthode Python que j'ai utilisée pour le mappage du XML:

Method ReadXML(xmlPath As %String) As %String [ Language = python ]
{
    import xml.etree.ElementTree as ET
    import iris
    import pandas as pd
<span class="hljs-keyword">try</span> :
    tree = ET.parse(xmlPath)
    root = tree.getroot()
    <span class="hljs-keyword">for</span> entry <span class="hljs-keyword">in</span> root.iter(<span class="hljs-string">"{http://www.w3.org/2005/Atom}entry"</span>):
        licitacion = {<span class="hljs-string">"titulo"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"resumen"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"idlicitacion"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"url"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"contratante"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"urlcontratante"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"estado"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"valorestimado"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"importetotal"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"importetotalsinimpuestos"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"clasificacion"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"localizacion"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"fechaadjudicacion"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"ganador"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"importeganadorsinimpuestos"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"importeganador"</span>: <span class="hljs-string">""</span>}
        <span class="hljs-keyword">for</span> tags <span class="hljs-keyword">in</span> entry:
            <span class="hljs-keyword">if</span> tags.tag == <span class="hljs-string">"{http://www.w3.org/2005/Atom}title"</span>:
                licitacion[<span class="hljs-string">"titulo"</span>] = tags.text
            <span class="hljs-keyword">if</span> tags.tag == <span class="hljs-string">"{http://www.w3.org/2005/Atom}summary"</span>:
                licitacion[<span class="hljs-string">"resumen"</span>] = tags.text
            <span class="hljs-keyword">if</span> tags.tag == <span class="hljs-string">"{http://www.w3.org/2005/Atom}id"</span>:
                licitacion[<span class="hljs-string">"idlicitacion"</span>] = tags.text
            <span class="hljs-keyword">if</span> tags.tag == <span class="hljs-string">"{http://www.w3.org/2005/Atom}link"</span>:
                licitacion[<span class="hljs-string">"url"</span>] = tags.attrib[<span class="hljs-string">"href"</span>]
            <span class="hljs-keyword">if</span> tags.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice-place-ext:schema:xsd:CommonAggregateComponents-2}ContractFolderStatus"</span>:
                <span class="hljs-keyword">for</span> detailTags <span class="hljs-keyword">in</span> tags:
                    <span class="hljs-keyword">if</span> detailTags.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice-place-ext:schema:xsd:CommonAggregateComponents-2}LocatedContractingParty"</span>:
                        <span class="hljs-keyword">for</span> infoContractor <span class="hljs-keyword">in</span> detailTags:
                            <span class="hljs-keyword">if</span> infoContractor.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}Party"</span>:
                                <span class="hljs-keyword">for</span> contractorDetails <span class="hljs-keyword">in</span> infoContractor:
                                    <span class="hljs-keyword">if</span> contractorDetails.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}PartyName"</span> :
                                        <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> contractorDetails:
                                            licitacion[<span class="hljs-string">"contratante"</span>] = name.text
                                    <span class="hljs-keyword">elif</span> contractorDetails.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}WebsiteURI"</span>:
                                        licitacion[<span class="hljs-string">"urlcontratante"</span>] = contractorDetails.text
                    <span class="hljs-keyword">elif</span> detailTags.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice-place-ext:schema:xsd:CommonAggregateComponents-2}ContractFolderStatusCode"</span>:
                        licitacion[<span class="hljs-string">"estado"</span>] = detailTags.text
                    <span class="hljs-keyword">elif</span> detailTags.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}ProcurementProject"</span>:
                        <span class="hljs-keyword">for</span> infoProcurement <span class="hljs-keyword">in</span> detailTags:
                            <span class="hljs-keyword">if</span> infoProcurement.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}BudgetAmount"</span>:
                                <span class="hljs-keyword">for</span> detailBudget <span class="hljs-keyword">in</span> infoProcurement:
                                    <span class="hljs-keyword">if</span> detailBudget.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}EstimatedOverallContractAmount"</span>:
                                        licitacion[<span class="hljs-string">"valorestimado"</span>] = detailBudget.text
                                    <span class="hljs-keyword">elif</span> detailBudget.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}TotalAmount"</span>:
                                        licitacion[<span class="hljs-string">"importetotal"</span>] = detailBudget.text
                                    <span class="hljs-keyword">elif</span> detailBudget.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}TaxExclusiveAmount"</span>:
                                        licitacion[<span class="hljs-string">"importetotalsinimpuestos"</span>] = detailBudget.text
                            <span class="hljs-keyword">elif</span> infoProcurement.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}RequiredCommodityClassification"</span>:
                                <span class="hljs-keyword">for</span> detailClassification <span class="hljs-keyword">in</span> infoProcurement:
                                    <span class="hljs-keyword">if</span> detailClassification.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}ItemClassificationCode"</span>:
                                        licitacion[<span class="hljs-string">"clasificacion"</span>] = detailClassification.text
                            <span class="hljs-keyword">elif</span> infoProcurement.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}RealizedLocation"</span>:
                                <span class="hljs-keyword">for</span> detailLocalization <span class="hljs-keyword">in</span> infoProcurement:
                                    <span class="hljs-keyword">if</span> detailLocalization.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}CountrySubentity"</span>:
                                        licitacion[<span class="hljs-string">"localizacion"</span>] = detailLocalization.text
                    <span class="hljs-keyword">elif</span> detailTags.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}TenderResult"</span>:
                        <span class="hljs-keyword">for</span> infoResult <span class="hljs-keyword">in</span> detailTags:
                            <span class="hljs-keyword">if</span> infoResult.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}AwardDate"</span>:
                                licitacion[<span class="hljs-string">"fechaadjudicacion"</span>] = infoResult.text
                            <span class="hljs-keyword">elif</span> infoResult.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}WinningParty"</span>:
                                <span class="hljs-keyword">for</span> detailWinner <span class="hljs-keyword">in</span> infoResult:
                                    <span class="hljs-keyword">if</span> detailWinner.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}PartyName"</span>:
                                        <span class="hljs-keyword">for</span> detailName <span class="hljs-keyword">in</span> detailWinner:
                                            <span class="hljs-keyword">if</span> detailName.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}Name"</span>:
                                                licitacion[<span class="hljs-string">"ganador"</span>] = detailName.text
                            <span class="hljs-keyword">elif</span> infoResult.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}AwardedTenderedProject"</span>:
                                <span class="hljs-keyword">for</span> detailTender <span class="hljs-keyword">in</span> infoResult:
                                    <span class="hljs-keyword">if</span> detailTender.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonAggregateComponents-2}LegalMonetaryTotal"</span>:
                                        <span class="hljs-keyword">for</span> detailWinnerAmount <span class="hljs-keyword">in</span> detailTender:
                                            <span class="hljs-keyword">if</span> detailWinnerAmount.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}TaxExclusiveAmount"</span>:
                                                licitacion[<span class="hljs-string">"importeganadorsinimpuestos"</span>] = detailWinnerAmount.text
                                            <span class="hljs-keyword">elif</span> detailWinnerAmount.tag == <span class="hljs-string">"{urn:dgpe:names:draft:codice:schema:xsd:CommonBasicComponents-2}PayableAmount"</span>:
                                                licitacion[<span class="hljs-string">"importeganador"</span>] = detailWinnerAmount.text
        iris.cls(<span class="hljs-string">"Ens.Util.Log"</span>).LogInfo(<span class="hljs-string">"Inquisidor.BP.XMLToLicitacion"</span>, <span class="hljs-string">"VectorizePatient"</span>, <span class="hljs-string">"Terminado mapeo "</span>+licitacion[<span class="hljs-string">"titulo"</span>])
        <span class="hljs-keyword">if</span> licitacion.get(<span class="hljs-string">"importeganador"</span>) <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">None</span> <span class="hljs-keyword">and</span> licitacion.get(<span class="hljs-string">"importeganador"</span>) <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-string">""</span>:
            iris.cls(<span class="hljs-string">"Ens.Util.Log"</span>).LogInfo(<span class="hljs-string">"Inquisidor.BP.XMLToLicitacion"</span>, <span class="hljs-string">"VectorizePatient"</span>, <span class="hljs-string">"Lanzando insert "</span>+licitacion[<span class="hljs-string">"titulo"</span>])
            stmt = iris.sql.prepare(<span class="hljs-string">"INSERT INTO INQUISIDOR_Object.Licitacion (Titulo, Resumen, IdLicitacion, URL, Contratante, URLContratante, Estado, ValorEstimado, ImporteTotal, ImporteTotalSinImpuestos, Clasificacion, Localizacion, FechaAdjudicacion, Ganador, ImporteGanadorSinImpuestos, ImporteGanador) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,TO_DATE(?,'YYYY-MM-DD'),?,?,?)"</span>)
            <span class="hljs-keyword">try</span>:
                rs = stmt.execute(licitacion[<span class="hljs-string">"titulo"</span>], licitacion[<span class="hljs-string">"resumen"</span>], licitacion[<span class="hljs-string">"idlicitacion"</span>], licitacion[<span class="hljs-string">"url"</span>], licitacion[<span class="hljs-string">"contratante"</span>], licitacion[<span class="hljs-string">"urlcontratante"</span>], licitacion[<span class="hljs-string">"estado"</span>], licitacion[<span class="hljs-string">"valorestimado"</span>], licitacion[<span class="hljs-string">"importetotal"</span>], licitacion[<span class="hljs-string">"importetotalsinimpuestos"</span>], licitacion[<span class="hljs-string">"clasificacion"</span>], licitacion[<span class="hljs-string">"localizacion"</span>], licitacion[<span class="hljs-string">"fechaadjudicacion"</span>], licitacion[<span class="hljs-string">"ganador"</span>], licitacion[<span class="hljs-string">"importeganadorsinimpuestos"</span>], licitacion[<span class="hljs-string">"importeganador"</span>])
            <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> err:
                iris.cls(<span class="hljs-string">"Ens.Util.Log"</span>).LogInfo(<span class="hljs-string">"Inquisidor.BP.XMLToLicitacion"</span>, <span class="hljs-string">"VectorizePatient"</span>, repr(err))
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Success"</span>
<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> err:
    iris.cls(<span class="hljs-string">"Ens.Util.Log"</span>).LogInfo(<span class="hljs-string">"Inquisidor.BP.XMLToLicitacion"</span>, <span class="hljs-string">"VectorizePatient"</span>, repr(err))
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Error"</span>

}

Une fois le mappage terminé, nous procédons à un simple insert avec l'enregistrement.

Pour le mappage en utilisant ObjectScript, j'ai utilisé la fonctionnalité %XML.TextReader , voyons la méthode:

Method OnRequest(pRequest As Ens.StreamContainer, Output pResponse As Ens.Response) As%Status
{
    set filename = pRequest.OriginalFilename

    set status=##class(%XML.TextReader).ParseFile(filename,.textreader)
    //check statusif$$$ISERR(status) {do$System.Status.DisplayError(status) quit}
    set tStatement = ##class(%SQL.Statement).%New()
    //iterate through document, node by nodewhile textreader.Read()
    {        

        if ((textreader.NodeType = "element") && (textreader.Depth = 2) && (textreader.Path = "/feed/entry")) {
            if ($DATA(licitacion))
            {                
                if (licitacion.ImporteGanador '= ""){
                    //set sc = licitacion.%Save()set myquery = "INSERT INTO INQUISIDOR_Object.LicitacionOS (Titulo, Resumen, IdLicitacion, URL, Contratante, URLContratante, Estado, ValorEstimado, ImporteTotal, ImporteTotalSinImpuestos, Clasificacion, Localizacion, FechaAdjudicacion, Ganador, ImporteGanadorSinImpuestos, ImporteGanador) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"set qStatus = tStatement.%Prepare(myquery)
                    if qStatus '= 1 {
                        write"%Prepare failed:"do$System.Status.DisplayError(qStatus)
                        quit
                    }
                    set rset = tStatement.%Execute(licitacion.Titulo, licitacion.Resumen, licitacion.IdLicitacion, licitacion.URL, licitacion.Contratante, licitacion.URLContratante, licitacion.Estado, licitacion.ValorEstimado, licitacion.ImporteTotal, licitacion.ImporteTotalSinImpuestos, licitacion.Clasificacion, licitacion.Localizacion, licitacion.FechaAdjudicacion, licitacion.Ganador, licitacion.ImporteGanadorSinImpuestos, licitacion.ImporteGanador)
                }                
            }
            set licitacion = ##class(Inquisidor.Object.LicitacionOS).%New()
        }        

        if (textreader.Path = "/feed/entry/title"){
            if (textreader.Value '= ""){
                set licitacion.Titulo = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/summary"){
            if (textreader.Value '= ""){
                set licitacion.Resumen = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/id"){
            if (textreader.Value '= ""){
                set licitacion.IdLicitacion = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/link"){            
            if (textreader.MoveToAttributeName("href")) {
                set licitacion.URL = textreader.Value                
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cbc-place-ext:ContractFolderStatusCode"){
            if (textreader.Value '= ""){
                set licitacion.Estado = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac-place-ext:LocatedContractingParty/cac:Party/cac:PartyName"){
            if (textreader.Value '= ""){
                set licitacion.Contratante = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac-place-ext:LocatedContractingParty/cac:Party/cbc:WebsiteURI"){
            if (textreader.Value '= ""){
                set licitacion.URLContratante = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:ProcurementProject/cac:BudgetAmount/cbc:EstimatedOverallContractAmount"){
            if (textreader.Value '= ""){
                set licitacion.ValorEstimado = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:ProcurementProject/cac:BudgetAmount/cbc:TotalAmount"){
            if (textreader.Value '= ""){
                set licitacion.ImporteTotal = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:ProcurementProject/cac:BudgetAmount/cbc:TaxExclusiveAmount"){
            if (textreader.Value '= ""){
                set licitacion.ImporteTotalSinImpuestos = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:ProcurementProject/cac:RequiredCommodityClassification/cbc:ItemClassificationCode"){
            if (textreader.Value '= ""){
                set licitacion.Clasificacion = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:ProcurementProject/cac:RealizedLocation/cbc:CountrySubentity"){
            if (textreader.Value '= ""){
                set licitacion.Localizacion = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:TenderResult/cbc:AwardDate"){
            if (textreader.Value '= ""){
                set licitacion.FechaAdjudicacion = $System.SQL.Functions.TODATE(textreader.Value,"YYYY-MM-DD")
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:TenderResult/cac:WinningParty/cac:PartyName/cbc:Name"){
            if (textreader.Value '= ""){
                set licitacion.Ganador = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:TenderResult/cac:AwardedTenderedProject/cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount"){
            if (textreader.Value '= ""){
                set licitacion.ImporteGanadorSinImpuestos = textreader.Value
            }
        }
        if (textreader.Path = "/feed/entry/cac-place-ext:ContractFolderStatus/cac:TenderResult/cac:AwardedTenderedProject/cac:LegalMonetaryTotal/cbc:PayableAmount"){
            if (textreader.Value '= ""){
                set licitacion.ImporteGanador = textreader.Value
            }
        }       
    }    
    // set resultEmbeddings = ..GenerateEmbeddings()Quit$$$OK
}

Les deux codes n'enregistreront dans la base de données que les concours qui ont déjà été résolus (pour lesquels le montant total gagnant a été communiqué).

Configuration de la production

Avec nos méthodes mises en œuvre dans les processus métier correspondants, il ne nous reste plus qu'à configurer la production pour notre test, ce qui nous permettra d'alimenter les deux méthodes. Il suffit d'ajouter deux services métier qui se limiteront à capturer les fichiers avec les informations XML et à les transmettre aux processus métier.

Pour éviter toute interférence lors de la capture et de la transmission des informations aux processus métier, nous allons créer deux services métier. La production se présentera comme suit:

Pour le test, nous allons introduire les concours publics du mois de février, soit un total de 91 fichiers avec 1,30 Go de données. Voyons comment se comportent les deux codes.

À vos marques...

Prêts...

C'est parti!

Résultats du mappage XML en ObjectScript

Commençons par le temps nécessaire au code ObjectScript pour mapper les 91 fichiers:

Le premier fichier a été démarré à 21:11:15, voyons quand le dernier fichier a été mappé:

Si nous regardons les détails du dernier message, nous pouvons voir la date finale du traitement:

L'heure finale est 21:17:43, ce qui donne un temps de traitement de 6 minutes et 28 secondes.

Résultats du mappage XML en Embedded Python

Répétez la même opération avec le processus qui utilise Python:

Début à 21:11:15 comme dans le cas précédent, voyons quand l'opération s'est terminée:

Voyons le message en détail pour connaître la fin exacte:

L'heure finale était 21:12:03, ce qui nous amène à un total de 48 secondes.

Eh bien, le gagnant est connu ! Dans ce round, Embedded Python a battu ObjectScript, du moins en ce qui concerne l'analyse XML. Si vous avez des suggestions ou des améliorations à apporter au code des deux méthodes, je vous encourage à les mettre dans les commentaires et je répéterai les tests pour vérifier les améliorations possibles.

Ce que nous pouvons dire, c'est qu'en ce qui concerne la supériorité évidente de la performance d'ObjectScript par rapport à Python... le mythe est brisé!

myth-busted – Mike Raffety, DTM, PID

0
0 35
Article Guillaume Rongier · Mars 26, 2025 7m read

Introduction

Une API REST (Representational State Transfer) est une interface qui permet de faire communiquer différentes applications entre elles via le protocole HTTP, en utilisant des opérations standard telles que GET, POST, PUT, et DELETE. Les API REST sont largement utilisées dans le développement de logiciels pour exposer des services accessibles par d'autres applications, permettant ainsi l'intégration entre différents systèmes.

Cependant, pour garantir que les APIs soient faciles à comprendre et à utiliser, une bonne documentation est essentielle. C'est là qu'OpenAPI entre en jeu.

OpenAPI est une norme de description pour les APIs RESTful. Elle permet de définir de manière structurée les fonctionnalités d'une API, en spécifiant les extrémités disponibles, les types de données acceptés et renvoyés, les paramètres requis et les réponses attendues. Toutes ces informations sont rassemblées dans un fichier de spécification (généralement avec une extension .yaml ou .json), qui peut être interprété par des outils automatisés pour générer du code, de la documentation, etc.

La spécification OpenAPI Specification est conçue pour être lisible par les machines et les humains, permettant la description, la production, la consommation et la visualisation de services web RESTful de manière standardisée. Par conséquent, un document OpenAPI représente une description formelle de l'API, utile à la fois pour les développeurs qui ont besoin de l'utiliser et pour les outils qui peuvent l'exploiter pour automatiser divers processus.

Pourquoi est-il utile de définir un fichier de spécifications?

L'adoption d'OpenAPI pour documenter une API offre plusieurs avantages, notamment:

  • Clarté: elle fournit une documentation détaillée et structurée, permettant aux développeurs de comprendre rapidement comment interagir avec l'API, quelles requêtes doivent être envoyées et quelles données peuvent être attendues en réponse.
  • Automatisation: la documentation peut être générée automatiquement à partir du code, et rester à jour avec tout changement d'API.
  • Interactivité: des outils tels que Swagger, une suite open source de documentation et de test d'API, incluent Swagger UI. Cela vous permet d'explorer et de tester les API directement depuis le navigateur, ce qui simplifie le développement, la vérification et la compréhension des API.
  • Normalisation: l'utilisation d'OpenAPI garantit que la documentation suit un format commun et reconnu, ce qui facilite l'intégration avec d'autres outils et services.

Comment créer un document OpenAPI?

Il existe deux approches principales pour générer un fichier de spécification OpenAPI:

  • Approche "code-first" (automatique): si une API REST a déjà été développée dans InterSystems IRIS, vous pouvez générer automatiquement la documentation OpenAPI sans écrire de fichier de spécification manuellement.
  • Approche "specification-first" (manuelle): dans ce cas, le fichier OpenAPI est écrit manuellement en YAML ou JSON, décrivant tous les points de terminaison, paramètres et réponses attendues. Cette approche est utile lorsque vous souhaitez définir l'API avant de la mettre en œuvre, ce qui facilite la conception et le partage avec d'autres développeurs ou parties prenantes.

Approche automatique

Il existe deux façons de générer automatiquement le fichier de spécification OpenAPI dans InterSystems IRIS.

Méthode 1 : Utilisation de la fonction GetWebRESTApplication

Une approche consiste à utiliser la fonction GetWebRESTApplication fournie par la classe %REST.API.
Un exemple pratique d'utilisation consiste à ajouter la fonction suivante dans la classe de répartition:

ClassMethod GenerateOpenAPI() As%Status
{
    // Le nom de l'application RESTSet webApplication = "MyAPP"// Remplacez par le nom de votre application web// Récupérez la documentation OpenAPI 2.0Set sc = ##class(%REST.API).GetWebRESTApplication("", webApplication, .swagger)
<span class="hljs-keyword">If</span> <span class="hljs-built_in">$$$ISERR</span>(sc) {
    <span class="hljs-keyword">Quit</span> sc  <span class="hljs-comment">// Si une erreur s'est produite, quittez la méthode</span>
}

<span class="hljs-comment">// Renvoyez la documentation au format JSON</span>
<span class="hljs-keyword">Set</span> <span class="hljs-built_in">%response.ContentType</span> = <span class="hljs-string">"application/json"</span>
<span class="hljs-keyword">Do</span> <span class="hljs-keyword">##class</span>(OMRREST.impl).<span class="hljs-built_in">%WriteResponse</span>(swagger.<span class="hljs-built_in">%ToJSON</span>()) 

<span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$OK</span>

}

Ajoutez en outre le chemin d'accès suivant à l'UrlMap:

  <Route Url="/openapi" Method="GET" Call="GenerateOpenAPI"/>

À ce stade, vous aurez tout ce qu'il vous faut pour générer le fichier de spécification à partir de votre classe d'envoi. Pour consulter la documentation, connectez-vous à l'URL indiquée (où MyWebapp est le nom de votre application web, tel que défini dans le portail de gestion):

<host>:<port>/MyWebapp/openapi

Le JSON ainsi généré représente la spécification OpenAPI de votre API. Après avoir exploré la deuxième méthode, nous verrons comment la visualiser et la tester dans Swagger.

Méthode 2 : Utilisation de l'API de gestion

Une autre façon de générer le fichier de spécification OpenAPI consiste à utiliser l' API de gestion InterSystems IRIS.

Pour appeler ce service, vous pouvez utiliser des outils tels que Postman, un outil de développement qui vous permet de tester, documenter et automatiser les API.
Postman fournit une interface simple et intuitive pour l'envoi de requêtes HTTP (GET, POST, PUT, DELETE, etc.), la visualisation des réponses, la gestion de l'authentification et la création de tests automatisés.

Pour formuler la requête à l'aide de Postman, procédez comme suit:

  1. Cliquez sur le bouton New  et créez une requête HTTP.
  2. Configurez la requête comme suit et envoyez-la:
    • Sélectionnez la méthode GET comme méthode HTTP.
    • Spécifiez l'URL dans le format suivant, en utilisant l' <baseURL> de votre instance:
      https://<baseURL>/api/mgmnt/v1/namespace/myapp
      Ici, namespace est le nom de l'espace de noms où vous avez créé d le service REST, et myapp et le nom de votre application.
    • Définissez la méthode d' Authorisation sur Basic Auth et fournissez le nom d'utilisateur et le mot de passe d'un utilisateur ayant un accès en lecture à l'espace de noms spécifié.

Une fois le JSON généré, il peut être visualisé et testé à l'aide d'outils tels que Swagger Editor.

{
   "info":{
      "title":"",
      "description":"",
      "version":"",
      "x-ISC_Namespace":"MyNamespace"
   },
   "basePath":"/MyWebapp",
   "paths":{
      "/loginForm":{
         "post":{
            "parameters":[
               {
                  "name":"payloadBody",
                  "in":"body",
                  "description":"Request body contents",
                  "required":false,
                  "schema":{
                     "type":"string"
                  }
               }
            ],
            "operationId":"loginForm",
            "x-ISC_ServiceMethod":"loginForm",
            "responses":{
               "default":{
                  "description":"(Unexpected Error)"
               },
               "200":{
                  "description":"(Expected Result)"
               }
            }
         }
      },
      "/refresh":{
         "post":{
            "parameters":[
               {
                  "name":"payloadBody",
                  "in":"body",
                  "description":"Request body contents",
                  "required":false,
                  "schema":{
                     "type":"string"
                  }
               }
            ],
            "operationId":"refresh",
            "x-ISC_ServiceMethod":"refresh",
            "responses":{
               "default":{
                  "description":"(Unexpected Error)"
               },
               "200":{
                  "description":"(Expected Result)"
               }
            }
         }
      },
      "/logout":{
         "post":{
            "parameters":[
               {
                  "name":"payloadBody",
                  "in":"body",
                  "description":"Request body contents",
                  "required":false,
                  "schema":{
                     "type":"string"
                  }
               }
            ],
            "operationId":"logout",
            "x-ISC_ServiceMethod":"logout",
            "responses":{
               "default":{
                  "description":"(Unexpected Error)"
               },
               "200":{
                  "description":"(Expected Result)"
               }
            }
         }
      },
      "/openapi":{
         "get":{
            "operationId":"GenerateOpenAPI",
            "x-ISC_ServiceMethod":"GenerateOpenAPI",
            "responses":{
               "default":{
                  "description":"(Unexpected Error)"
               },
               "200":{
                  "description":"(Expected Result)"
               }
            }
         }
      }
   },
   "swagger":"2.0"
}

Approche manuelle

L'approche manuelle pour générer un document OpenAPI consiste à écrire manuellement le fichier de spécification au format YAML ou JSON. Cette approche est particulièrement utile lorsque vous souhaitez contrôler entièrement la conception de l'API avant sa mise en œuvre, ou lorsque vous documentez une API déjà existante sans recourir à des outils automatisés.

Pour rédiger le fichier de spécification OpenAPI, vous pouvez vous référer à , la documentation officielle de la version 2.0 de la spécification OpenAPI, où vous trouverez des renseignements sur les champs obligatoires et sur la manière de décrire les points de terminaison, les paramètres, les réponses, etc. Ce guide détaillé vous aidera à comprendre comment structurer correctement le fichier YAML ou JSON afin de respecter les normes OpenAPI.

Un bon exemple d'utilisation de cette approche est la création d'un service REST à l'aide des méthodes décrites dans la documentation officielle d'InterSystems IRIS.
Vous trouverez une introduction au développement et à la configuration d'une application REST dans IRIS sur cette page de la documentation, qui décrit étape par étape les méthodes nécessaires pour exposer une application RESTful avec IRIS.

2
1 86
Article Iryna Mykhailova · Mars 7, 2025 3m read

Je me suis lancé un défi : trouver un moyen de faire en sorte qu'une variable se surveille elle-même pour une certaine valeur et fasse quelque chose lorsqu'elle atteint cette valeur sans avoir à la vérifier à chaque fois que quelque chose la touche. En gros, un moyen de dire "à un moment donné pendant l'exécution de ce code, si x = 0 (ou quelle que soit la condition) faire ceci". La classe avec laquelle j'ai fini par surveiller un %Status :

0
0 42
InterSystems officiel Adeline Icard · Fév 11, 2025

Tout d'abord, permettez-moi de souhaiter une bonne année à la Communauté des Développeurs ! Nous espérons vous apporter beaucoup de bonnes choses cette année, et aujourd'hui, j'aimerais vous présenter la dernière version de l'extension Intersystems Language Server pour VS Code. La plupart des améliorations de Language Server sont expérimentées via l'interface utilisateur de l'extension ObjectScript, vous n'êtes donc peut-être pas au courant des nombreuses améliorations dans des domaines tels qu'Intellisense et les survols qui ont été publiées tout au long de l'année 2024. Veuillez lire

0
0 39
InterSystems officiel Adeline Icard · Jan 21, 2025

InterSystems a corrigé un défaut qui provoque l'introduction d'enregistrements de base de données et de journaux non valides lors de l'utilisation d'une syntaxe $LIST spécifique. La probabilité de rencontrer ce défaut est très faible, mais les impacts opérationnels peuvent être importants.

Produits concernés

0
0 32
Article Sylvain Guilbaud · Déc 26, 2024 3m read

Traduit du concours d'articles de la communauté espagnole.

Suite au dernier concours de programmation sur OEX j'ai eu une observation surprenante.
Il existait des applications presque exclusives basées sur l'IA en combinaison avec des modules Py précuits.
Mais en creusant plus profondément, tous les exemples utilisaient les mêmes éléments techniques d'IRIS.

Du point de vue d'IRIS, c'était à peu près la même chose que la recherche de texte
ou la recherche d'images ou d'autres motifs.  Cela s'est terminé par des méthodes presque échangeables.

1
0 40
Article Sylvain Guilbaud · Jan 2, 2025 10m read

Votre mission

Imaginons que vous êtes un espion international qui consacre sa vie à protéger les habitants de notre planète contre les dangers. La mission suivante vous est confiée:

Cher agent IRIS,

Nous sommes désolés d'interrompre vos vacances aux Bahamas, mais notre agent à Londres vient de nous informer qu'une "bombe à explosion retardée" est prête à exploser dans une zone très peuplée de Los Angeles. Selon nos informateurs, la "bombe à explosion retardée" devrait se déclencher à 15h14 aujourd'hui.

Dépêchez-vous, les citoyens comptent sur vous!

Le problème

Alors que vous vous précipitez et vous préparez à partir pour Los Angeles, vous vous rendez compte qu'il vous manque un renseignement essentiel : cette "bombe à explosion retardée" explosera-t-elle à 15h14 heure des Bahamas ou à 15h14 heure de Los Angeles? ...ou peut-être même à 15h14 heure de Londres.

Vous comprenez bien vite que l'heure fournie (15h14) ne vous donne pas assez de renseignements pour déterminer le moment où vous devez vous rendre à Los Angeles.

L'heure indiquée (15h14) était ambiguë. Vous avez besoin de plus de renseignements pour déterminer une heure exacte.

Quelques solutions

Lorsque vous réfléchissez au problème, vous vous rendez compte qu'il existe des méthodes pour surmonter l'ambiguïté de l'heure indiquée qui vous a été fournie:

  1. Votre informateur aurait pu vous fournir le lieu où l'heure locale était 3:14 PM. Par exemple, Los Angeles, les Bahamas, ou Londres.

  2. Votre informateur aurait pu utiliser un standard telle que l'UTC (temps universel coordonné) pour vous fournir un décalage par rapport à un lieu convenu (tel que Greenwich, Londres).

La fin heureuse

Vous téléphonez à votre informateur et confirmez que l'heure fournie était bien 15h14 heure de Los Angeles. Vous pouvez vous rendre à Los Angeles, désamorcer la "bombe à explosion retardée" avant 15h14, et retourner rapidement aux Bahamas pour y terminer vos vacances.

Le but

Quel est donc le but de cet exercice de réflexion? Je doute qu'aucun d'entre nous soit confronté au problème présenté ci-dessus, mais si vous travaillez avec une application ou un code qui déplace des données d'un lieu à un autre (en particulier si les lieux se trouvent dans des fuseaux horaires différents), vous devez savoir comment gérer les dates-heures et les fuseaux horaires.

Les fuseaux horaires, C'EST DUR!

Eh bien, les fuseaux horaires ne sont pas si mauvais. Ce sont l'heure d'été et les périmètres politiques qui rendent les fuseaux horaires si difficiles à gérer.

Je croyais avoir toujours compris l'idée "générale" des fuseaux horaires: le globe est divisé en tranches verticales par fuseau horaire, où chaque fuseau horaire est en retard d'une heure par rapport au fuseau horaire situé à l'Est.

Les fuseaux horaires sur la carte du monde (simplification)

Bien que cette simplification soit valable pour de nombreux endroits, il existe malheureusement de nombreuses exceptions à cette règle.

Fuseaux horaires du monde (Wikipedia) Référence: Fuseaux horaires du monde (Wikipedia)

Représentation du temps UTC ("l'origine")

Pour simplifier la communication de l'heure spécifique, le monde a décidé d'utiliser l'UTC (le temps universel coordonné). Ce standard fixe "l'origine" à la longitude 0° qui passe par Greenwich, Londres.

Définition du "décalage"

En utilisant le temps universel coordonné (UTC) comme base, tous les autres fuseaux horaires peuvent être définis par rapport à l'UTC. Cette relation est appelée décalage UTC.

Si vous connaissez l'heure locale et le décalage, vous n'avez plus d'heure ambiguë (comme dans notre exemple d'espionnage ci-dessus) ; vous avez une heure définie et spécifique, sans ambiguïté.

Le format type utilisé pour indiquer le décalage UTC est le suivant: ±HHMM[SS[.ffffff]].

  • Le symbole moins - indique un décalage à l'ouest de l'UTC.
  • Le signe plus + indique un décalage à l'est de l'UTC..
  • HH indique les heures (avec un zéro initial)
  • MM indique les minutes (avec un zéro initial)
  • SS indique les secondes (avec un zéro initial)
  • .ffffff indique les fractions de secondes

Par exemple, en Amérique, le fuseau horaire de l'Est (EST) est défini comme -0500 UTC. Cela signifie que toutes les localités situées dans le fuseau horaire EST sont en retard de 5 heures par rapport à l'UTC. Si l'heure est 9:00 PM à UTC, l'heure locale à EST est 4:00 PM.

Dans le fuseau horaire central occidental d'Australie (ACWST), le décalage est défini comme +0845 UTC. Si l'heure est 21h00 à UTC, l'heure locale d'EST est 16h00.

Heure d'été

Revenons aux cartes des fuseaux horaires ci-dessus. Vous y trouverez de nombreux fuseaux horaires qui suivent les frontières politiques des pays et des régions. Cela complique légèrement le calcul des fuseaux horaires, mais c'est assez facile à comprendre.

Malheureusement, il y a un autre élément à prendre en compte lorsque l'on travaille avec des heures et des fuseaux horaires. Regardons Los Angeles.

Cette carte indique que le décalage UTC pour Los Angeles est de -8 en Standard Time. L'heure normale est généralement suivie pendant les mois d'hiver, tandis que l'heure d'été est généralement suivie pendant les mois d'été.

L'heure d'été (en anglais; Daylight Savings Time (DST) avance les horloges d'un fuseau horaire donné (généralement d'une heure pendant les mois d'été). Les régions politiques peuvent choisir de suivre l'heure d'été pour plusieurs raisons (économies d'énergie, meilleure utilisation de la lumière du jour, etc.) La difficulté et la complexité de l'heure d'été résident dans le fait que l'heure d'été n'est pas appliquée de manière uniforme dans le monde entier. Selon votre situation géographique, votre région peut suivre ou non l'heure d'été.

Base de données de fuseaux horaires

La combinaison des frontières politiques et de l'heure d'été augmentant considérablement la complexité de la détermination d'une heure spécifique, une base de données des fuseaux horaires est nécessaire pour faire correspondre correctement les heures locales à des heures spécifiques par rapport à l'UTC. La base de données des fuseaux horaires de l'IANA (Internet Assigned Numbers Authority) est la source commune de renseignements sur les fuseaux horaires utilisée par les systèmes d'exploitation et les langages de programmation.

La base de données comprend les noms et alias de tous les fuseaux horaires, des renseignements sur le décalage, des renseignements sur l'utilisation de l'heure d'été, les abréviations des fuseaux horaires et les plages de données auxquelles les différentes règles s'appliquent.

Des copies et des renseignements concernant la base de données sur les fuseaux horaires sont disponibles sur le site web de l'IANA.

La plupart des systèmes UNIX disposent d'une copie de la base de données qui est mise à jour par le gestionnaire de paquetages du système d'exploitation (généralement installé dans /usr/share/zoneinfo). Certains langages de programmation ont la base de données intégrée. D'autres la rendent disponible par le biais d'une bibliothèque ou peuvent lire la copie de la base de données du système.

Noms et identifiants des fuseaux horaires

La base de données des fuseaux horaires contient un grand nombre de noms et d'alias pour des fuseaux horaires spécifiques. La plupart des saisies incluent un pays (ou un continent) et une grande ville dans le nom. Par exemple:

  • Amérique/New_York
  • Amérique/Los_Angeles
  • Europe/Rome
  • Australie/Melbourne

Conversion et formatage à l'aide d'ObjectScript

Ainsi, voici ce que nous savons:

  • les heures locales (heures ambiguës sans décalage ni emplacement)
  • les décalages UTC (le décalage relatif d'un horodatage ou d'un emplacement par rapport à l'« origine » UTC à Greenwich, Londres)
  • l'heure d'été (une tentative d'aider la civilisation au détriment des décalages de fuseaux horaires)
  • base de données des fuseaux horaires (qui contient des renseignements sur les fuseaux horaires et le respect de l'heure d'été dans de nombreux lieux et régions).

Sachant cela, comment pouvons-nous travailler avec les heures-dates et les fuseaux horaires en ObjectScript?

***Note: Je crois que toutes les affirmations suivantes sont vraies à propos d'ObjectScript, mais n'hésitez pas à me faire savoir si j'ai mal expliqué comment ObjectScript fonctionne avec les fuseaux horaires et les décalages.

Variables et fonctions intégrées

Si vous avez besoin de convertir des horodatages entre différents formats dans le fuseau horaire du processus exécutant IRIS, les fonctionnalités intégrées d'ObjectScript devraient être suffisantes. Voici une brève liste des variables/fonctions relatives au temps dans ObjectScript:

  • $ZTIMESTAMP / $ZTS

    • Format interne d'IRIS en tant que valeur UTC (décalage +0000).
    • Format: ddddd,sssss.fffffff
  • $NOW(tzmins)

    • Heure locale du système actuel avec le décalage de tzmins donné par rapport à UTC.
    • Heure d'été n'est pas prise en compte.
    • Par défaut, tzmins est basé sur la variable $ZTIMEZONE.
    • Format: ddddd,sssss.fffffff
  • $HOROLOG

    • Heure locale actuelle du système (basée sur $ZTIMEZONE), avec prise en compte de l'heure d'été.
    • Format: ddddd,sssss.fffffff
  • $ZTIMEZONE

    • Renvoie ou définit le décalage UTC local du système en minutes.
  • $ZDATETIME() / $ZDT()

    • Conversion du format $HOROLOG en un format d'affichage spécifique.
    • Peut être utilisé pour la conversion de l'heure locale du système à l'heure UTC (+0000).
  • $ZDATETIMEH() / $ZDTH()

    • Conversion d'une chaîne de date au format interne $HOROLOG.
    • Peut être utilisé pour convertir l'heure UTC (+0000) en heure locale.

Pour autant que je sache, ces fonctionnalités ne peuvent manipuler les dates qu'en utilisant le fuseau horaire du système local. Il ne semble pas y avoir de moyen de travailler avec des fuseaux horaires arbitraires en ObjectScript.

Accès à la bibliothèque tz sur Open Exchange

Pour faciliter la conversion vers et depuis des fuseaux horaires arbitraires, j'ai créé la bibliothèque de conversion de fuseaux horaires ObjectScript tz - ObjectScript Time Zone Conversion Library.

Cette bibliothèque accède à la base de données des fuseaux horaires installée sur votre système afin d'offrir un support pour la conversion des horodatages entre les fuseaux horaires et les formats.

Par exemple, si vous disposez de l'heure locale de Los Angeles (Amérique/Los_Angeles), vous pouvez la convertir dans le fuseau horaire utilisé aux Bahamas (Amérique/New_York) ou dans le fuseau horaire utilisé à Londres (Europe/Londres):

USER>zw ##class(tz.Ens).TZ("2024-12-20 3:14 PM", "America/Los_Angeles", "America/New_York")
"2024-12-20 06:14 PM"

USER>zw ##class(tz.Ens).TZ("2024-12-20 3:14 PM", "America/Los_Angeles", "Europe/London")
"2024-12-20 11:14 PM"

Si l'on vous donne un horodatage avec un décalage, vous pouvez le convertir en heure locale à Eucla, Australie (Australie/Eucla), même si vous ne connaissez pas le fuseau horaire d'origine:

USER>zw ##class(tz.Ens).TZ("2024-12-20 08:00 PM -0500", "Australia/Eucla")
"2024-12-21 09:45 AM +0845"

Si vous travaillez avec des messages HL7, la bibliothèque tz dispose de plusieurs méthodes associées aux règles d'interopérabilité et aux DTL pour vous aider à convertir facilement les fuseaux horaires, les heures locales, les heures avec décalage, etc.:

// Conversion de l'heure locale d'un fuseau horaire à l'autre 	 
set datetime = "20240102033045"
set newDatetime = ##class(tz.Ens).TZ(datetime,"America/New_York","America/Chicago")

// Conversion de l'heure locale en décalage 	 
set datetime = "20240102033045"
set newDatetime = ##class(tz.Ens).TZOffset(datetime,"America/Chicago","America/New_York")

// Conversion du décalage en heure locale 	 
set datetime = "20240102033045-0500"
set newDatetime = ##class(tz.Ens).TZLocal(datetime,"America/Chicago")

// Conversion vers un format alternatif au HL7 	 
set datetime = "20240102033045-0500"
set newDatetime = ##class(tz.Ens).TZ(datetime,"America/Chicago",,"%m/%d/%Y %H:%M:%S %z")

Résumé

Je vous remercie de m'avoir suivi dans ce "voyage à travers le monde" où nous avons rencontré des fuseaux horaires, l'heure d'été, les cartes du monde et les "bombes à explosion retardée". J'espère que ce travail vous a permis d'éclairer (et de simplifier) les nombreuses complexités liées à l'utilisation des dates et des fuseaux horaires.

Consultez la bibliothèque tz - ObjectScript Time Zone Conversion Library et faites-moi savoir si vous avez des questions (ou des corrections/clarifications à propos de quelque chose que j'ai dit ici.

Merci!

Références / Liens intéressants

0
0 85
Article Lorenzo Scalese · Nov 21, 2024 8m read

Dans l'article précédent. Pratiques des membres de la classe et leur exécution au sein de Embedded Python. WNous allons maintenant aborder le processus de changement d'espace de noms, d'accès aux variables globales, de traversée et d'exécution de routine  au sein de Embedded Python.

Avant de passer aux autres fonctions, examinons brièvement la fonction execute du paquet iris. Cette fonction est particulièrement utile pour l'exécution de fonctions ObjectScript arbitraires et l'invocation de classes.

>>> b = iris.execute('return $Piece("test^aaaa","^",2)')
>>> b
'aaaa'
>>> b = iris.execute('return $Extract("123456",2,5)')
>>> b
'2345'
>>> b = iris.execute('return $Length(123456)')
>>> iris.execute('write ##Class(%SYSTEM.SYS).NameSpace()')
LEARNING>>>
>>> b = iris.execute('return ##Class(%SYSTEM.SYS).NameSpace()')
>>> b
'LEARNING'

Commençons!

4. Changement d'espace de noms

Il est souvent nécessaire de changer d'espace de noms en cours d'exécution. Toutefois, contrairement à IRIS, il n'est pas possible de changer directement d'espace de noms dans Embedded Python. Il est donc essentiel d'utiliser les définitions de classes existantes ou de créer une méthode wrapper pour faciliter le changement d'espace de noms.  

ClassMethod SwitchNM() [ Language = python ]
{
    import iris
    print(iris.cls('%SYSTEM.SYS').NameSpace())
    print(iris.system.Process.SetNamespace("USER"))
    try:
        iris.cls('User.EmbeddedPython').pyGetTemplateString()
    except RuntimeError as e:
        print("Wrong NameSpace",e)
}

 

5. Globale

Pour utiliser les capacités d'une globale pour les données de la traversée ou pour l'extraction directe d'informations à partir de systèmes globaux existants, plutôt que par le biais de SQL ou d'objets dans Embedded Python, on peut y accéder directement en employant la fonction gref du paquetage iris. Pour définir ou obtenir des valeurs globales, la fonction gref peut être utilisée pour établir une référence à la variable globale et assigner directement des valeurs dans Python.

 
iris.gref
class gref(builtins.object)
 |  Objet de référence global d'InterSystems IRIS.
 |  UUtilisez la méthode iris.gref() pour obtenir une référence à une globale
 |
 |  Les méthodes sont définies ci-dessous:
 |
 |  __delitem__(self, key, /)
 |      Suppression de self[key].
 |
 |  __getitem__(self, key, /)
 |      Renvoie de self[key].
 |
 |  __len__(self, /)
 |      Renvoie de len(self).
 |
 |  __repr__(self, /)
 |      Renvoie de repr(self).
 |
 |  __setitem__(self, key, value, /)
 |      Mise à la valeur de self[key].
 |
 |  __str__(self, /)
 |      Renvoie de str(self).
 |
 |  data(self, key)
 |      Étant donné les clés d'une globale sous forme de liste, renvoie son état.
 |      Exemple : x = g.data([i,j]) attribue à x les valeurs 0,1,10,11 0-si indéfini, 1-défini, 10-indéfini mais a des descendants, 11-a une valeur et des descendants
 |
 |  get(self, key)
 |      Étant donné les clés d'un global sous forme de liste, renvoie la valeur stockée à ce nœud de globales.
 |      Exemple : x = g.get([i,j]) attribue à x la valeur stockée à la clé i,j de globale g.
 |
 |  getAsBytes(self, key)
 |      Étant donné les clés d'une globale sous forme de liste, renvoie une chaîne de caractères stockée à ce nœud de la globale, sous forme d'octets.
 |      Exemple : x = g.getAsBytes([i,j]) attribue à x la valeur stockée à la clé i,j de la globale g, sous forme d'octets.
 |
 |  keys(self, key)
 |      Traverse une globale à partir de la clé spécifiée, en retournant chaque clé dans la globale.
 |      Exemple : for key in g.keys([i, j]) traverse g à partir de la clé i,j, en retournant chaque clé à son tour. Deuxième argument facultatif 1 ou -1, si -1 inverse l'ordre retourné
 |
 |  kill(self, key)
 |      Étant donné les clés d'une globale sous forme de liste, supprime ce nœud de la globale et sa sous-arborescence.
 |      Exemple : g.kill([i,j]) supprime le nœud stocké à la clé i,j de la globale g et tous ses descendants.
 |
 |  order(self, key)
 |      Étant donné les clés d'une globale sous forme de liste, renvoie la clé suivante de la globale, second argument facultatif 1 ou -1, si -1 renvoie la clé précédente.
 |      Exemple : j = g.order([i,j]) attribue à j la clé de deuxième niveau suivante de la globale g.
 |
 |  orderiter(self, key)
 |      Traverse une globale à partir de la clé spécifiée, en renvoyant la clé et la valeur suivantes sous la forme d'un tuple.
 |      Exemple : pour (clé, valeur) dans g.orderiter([i,j]) traverse g à partir de la clé i,j, en renvoyant la clé et la valeur suivantes. Deuxième argument facultatif : 1 ou -1, si -1, l'ordre retourné est inversé.
 |
 |  query(self, key)
 |      Traverse une globale à partir de la clé spécifiée, en renvoyant chaque clé et chaque valeur sous la forme d'un tuple.
 |      Exemple : pour (clé, valeur) dans g.query([i,j]) traverse g à partir de la clé i,j, en renvoyant chaque clé et chaque valeur à tour de rôle. Deuxième argument facultatif : 1 ou -1, si -1, l'ordre retourné est inversé.
 |
 |  set(self, key, value)
 |      Étant donné les clés d'une globale sous forme de liste, définit la valeur stockée à cette clé de la globale.
 |      Exemple : g.set([i,j], 10) fixe la valeur du nœud à la clé i,j de la globale g à 10
 |
 |  ----------------------------------------------------------------------
 |  Les méthodes statiques sont définies ci-dessous:
 |
 |  __new__(*args, **kwargs) from builtins.type
 |      Création et retour d'un nouvel objet.  Consultez help(type) pour obtenir une signature précise.

5.1 Définition des valeurs globales

ClassMethod SetGlobal() [ Language = python ]
{
import iris
#création d'une référence globale
g = iris.gref('^mygbl') 
g[1],g[2]='Mon','Tue'
g["95752455",1]=iris.execute('return $LFS("Ashok,55720,9639639639,test@gmail.com",",")')
g["85752400",1]=iris.execute('return $LB("Test","9517539635","t@gmail.com")')
g["test","c1"]=iris.execute('return ##Class(MyLearn.EmbeddedPython).executeAndGetResult()') # method wil return some listbuild values# déclaration de valeurs à l'aide de la fonction set
g.set([3],'Wed')
g.set([3,1,1],'Test multilevel')
}

5.2 Obtention des valeurs globales
Récupérez les valeurs globales à partir de python directement en utilisant la méthode subscripts ou get.

ClassMethod GetGlobal() [ Language = python ]
{
    import iris
    #obtient une référence globale
    g = iris.gref('^mybgl') 
    # obtention de valeurs
    print(g[3,1,1])
    print(g.get([2,1]))
    print(g["95752455",1])
}

5.3 Traversée 

order - Traverser la globale est essentiel pour collecter plusieurs niveaux de données de la globale. Cette commande en Embedded Python  order fonctionne de manière similaire à la commande $Order en utilisant la fonction order du fichier iris.gref. Au départ, il est nécessaire d'établir une référence à l'entité globale qui doit être traversée.

Traversée à un seul niveau d'indice

ClassMethod DollarOrder() [ Language = python ]
{
    import iris
    g = iris.gref('^MyLearn.EmbeddedPythonD') # I use my persistent class global
    key = ''
    while True:
        key = g.order([key])
        if key == None:
            breakprint(f'{key} {g.get([key])}')
}

Traversée à plusieurs niveaux d'indices

 
global
zw ^mygbl
^mygbl(1)="Mon"
^mygbl(2)="Tue"
^mygbl(3)="Wed"
^mygbl(3,1,1)="Test multilevel"
^mygbl(85752400,1)=$lb("Test","9517539635","t@gmail.com")
^mygbl(95752455,1)=$lb("Ashok","55720","9639639639","test@gmail.com")
^mygbl("test","c1")=$lb("Test","8527538521","pylearn@gmail.com")
 
ClassMethod DollarOrderMultiLevel() [ Language = python ]
{
 import iris
 g = iris.gref('^mygbl')
 key1= ''whileTrue:
 	key1 = g.order([key1])
 	if key1== None:
 		break
 	key2 = ''whileTrue:
 		key2 = g.order([key1,key2])
 		if key2 == None:
 			break
 		value = g.get([key1,key2])
 		print(key1,key2,value)
}

query - La fonction de requête à partir de iris.gref est similaire à $query. Cette fonction is rassemble toutes les valeurs globales en tuples. Le résultat du tuple contient les identifiants dans la liste et les valeurs sont le tuple suivant. Vous pouvez consulter l'exemple de tuple ci-dessous 

 
tuple
ex: 
zw ^mybgl
^mybgl(1)="Mon"
^mybgl(2)="Tue"
^mybgl(3)="Wed"
^mybgl(3,1,1)="Test multilevel"
^mybgl(95752455,1)=$lb("Ashok","55720","9639639639","test@gmail.com")

Python tuple : ( [ids], data)
(['1'], 'Mon')
(['2'], 'Tue')
(['3'], 'Wed')
(['3', '1', '1'], 'Test multilevel')
(['95752455', '1'], '\x07\x01Ashok\x07\x0155720\x0c\x019639639639\x10\x01test@gmail.com')

ClassMethod DollarQuery() [ Language = python ]
{
 	import iris
 	g = iris.gref('^mygbl')
 	key = g.query()#cela renverra des tuples de tous les indicesfor x in key:
 		print(x) # résultat (['3', '1', '1'], 'Test multilevel')
}

data - la fonction data Vérifie si l'indice donné existe dans le global et renvoie les valeurs $data en utilisant la fonction de données

ClassMethod DollarData() [ Language = python ]
{
    import iris
    g = iris.gref('^mygbl')
    key1= ''
    print(g.data([1]))
}

 

6. Routines

En outre, il est essentiel d'implémenter les membres de la classe. Nous devons exécuter les routines dans le cadre de la mise en œuvre pour les systèmes de base de code hérités et d'autres situations connexes. Par conséquent, il existe une fonction spécifique dans le paquet de la bibliothèque iris qui permet l'invocation de routines à partir de Embedded Python grâce à l'utilisation de la fonction routine.

 
myirispython.mac
myirispython
 123
 q
ir1
 "running ir1"
 q
add(p1,p2) public{
return p1+p2
}
sub(p1,p2)
 c= p1-p2
ClassMethod RunRoutines() [ Language = python ]
{
    import iris
    iris.routine('^myirispython')
    iris.routine('add^myirispython',1,2) # same aswrite$$add^myirispython(1,2)
}

En outre, vous pouvez également exécuter la routine à l'aide de la fonction d'exécution. iris.execute('do ^myirispython')

remarque : si la routine n'est pas trouvée 
>>> iris.routine('^myirispythonT')
Traceback (dernier appel récent):
  File "<input>", line 1, in <module>
RuntimeError: Routine introuvable

Les autres sujets seront abordés dans le prochain article.

0
0 40
Article Lorenzo Scalese · Nov 18, 2024 8m read

Bonjour la communauté,

Dans cet article, je vais décrire et illustrer le processus de mise en œuvre d'ObjectScript au sein de Embedded Python. Cette discussion fera également référence à d'autres articles relatifs à Embedded Python, et répondra aux questions qui ont été utiles à mon apprentissage.

Comme vous le savez peut-être, l'intégration des fonctionnalités de Python dans IRIS est possible depuis un certain temps. Cet article se concentrera sur la manière dont ObjectScript peut être incorporé de manière transparente à Embedded Python.

Essentiellement, Embedded Python sert d'extension qui permet une écriture et une exécution indépendantes. Il permet l'intégration transparente du code Python avec ObjectScript et vice versa, permettant aux deux de s'exécuter dans le même contexte. Cette fonctionnalité améliore considérablement les capacités de votre implémentation.

Pour commencer, vous devez spécifier le langage de votre code Python dans la définition de la classe en utilisant le mot-clé "language" [language = "python"]. Une fois cette étape franchie, vous êtes prêt à écrire votre code Python.

import iris - Ce paquet iris est une bibliothèque Python essentielle qui facilite la communication avec les classes, routines, globales et SQL de l'API native d'InterSystems. Ce paquet est facilement disponible par défaut. Quoi qu'il en soit, il est nécessaire d'importer ce paquet au début de votre code Python si vous souhaitez interagir avec IRIS.

Quelques notes importantes avant d'écrire

  • Vous pouvez utiliser une variable spéciale python __name__ pour référencer le nom de classe dans la définition de classe.
  • Use _ for %Methods ex: %New  == _New , %OpenId == _OpenId

Commençons

Mise en œuvre des éléments d'une classe en Python intégré

1.  Objets et Propriétés

Cette partie est essentielle car elle couvre le processus d'initialisation d'un nouvel objet, la modification des valeurs des objets existants et la configuration des propriétés dans des contextes statiques et dynamiques. Créez votre propre définition de classe et utilisez les propriétés littérales simples

1.1 initialisation new d'un nouvel objet / Modification d'un objet existant

Utilisez _New pour initialiser un nouvel objet et _OpenId(id) pour modifier l'objet existant

ClassMethod SaveIRISClsObject() [ Language = python ]
{
 #cette méthode appelle la méthode de rappel %OnNew et récupère l'objetimport iris
 try:
     iris_obj =  iris.cls(__name__)._New()
     ifnot iris.cls(__name__).IsObj(iris_obj):
      #IsObj est la méthode wrapper d'objectscript : elle contient $Isobject()raise ReferenceError('Object Initlize Error')
 except ReferenceError as e:
     print(e)
     return#définition des propriétés de l'objet et enregistrement des valeurs 
 iris_obj.Name = 'Ashok'
 iris_obj.Phone = 9639639635
 status = iris_obj._Save()
 print(status)
 return status
}

1.2 Accès  aux propriétés

Avant de procéder à la partie sur les propriétés, il est important de noter que le type de données IRIS diffère des types de données Python et que, par conséquent, les types de données de collecte IRIS ne peuvent pas être utilisés directement dans Python. Pour résoudre ce problème, InterSystems a proposé une solution complète pour convertir les types de données IRIS en formats compatibles avec Python, tels que les listes, les ensembles et les tuples. Pour ce faire, il suffit d'importer le module "builtins" dans la base de code IRIS, en utilisant les méthodes de classe ##class(%SYS.Python).Builtins() ou en définissant les builtins = ##class(%SYS.Python).Import("builtins"). Je reviendrai sur ce point dans les prochaines parties.

J'utilise donc cette méthode pour convertir les propriétés $LB en liste  python afin d'accéder aux propriétés au moment de l'exécution en python

LEARNING>Set pyList = ##class(%SYS.Python).ToList($LB("Name","Phone","City"))
 
LEARNING>zw pyList
pyList=5@%SYS.Python  ; ['Name', 'Phone', 'City']  ; <OREF>
ClassMethod GetProperties() [Language = objectscript]
{
    set pyList = ##class(%SYS.Python).ToList($LB("Name","Phone","City"))
    do..pyGetPropertiesAtRunTime(pyList)
}
ClassMethod pyGetPropertiesAtRunTime(properties) [ Language = python ]
{
    import iris
    iris_obj = iris.cls(__name__)._OpenId(1)
    for prop in properties:
        print(getattr(iris_obj,prop))
}

 

1.3 Définition des propriétés au moment de l'exécution.

J'utilise ce dictionnaire python pour désigner ma propriété en tant que clé et, avec les valeurs de propriété correspondantes servant de valeurs dans ce dictionnaire. Vous pouvez vous référer au code fourni ci-dessous et à l'article de la communauté concernant ce jeu de propriétés .

ClassMethod SetProperties()
{
	Set pyDict = ##class(%SYS.Python).Builtins().dict()
	do pyDict.setdefault("Name1", "Ashok kumar")
	do pyDict.setdefault("Phone", "9639639635")
	do pyDict.setdefault("City", "Zanesville")
	Set st = ..pySetPropertiesAtRunTime(pyDict)
}

ClassMethod pySetPropertiesAtRunTime(properties As%SYS.Python) [ Language = python ] { import iris iris_obj = iris.cls(name)._New() for prop in properties: setattr(iris_obj, prop,properties[prop])

status = iris_obj._Save()
<span class="hljs-keyword">return</span> status

}

1.4 Contexte de partage d'objets

Comme j'ai indiqué précédemment, Python et ObjectScript opèrent dans le même contexte de mémoire et partagent des objets. Cela implique que vous pouvez créer ou ouvrir un objet dans la classe InCache et, par la suite, le définir ou le récupérer dans la classe Python.

ClassMethod ClassObjectAccess() [Language = objectscript]
{
	Set obj = ..%OpenId(1)
	Write obj.PropAccess(),! ; prints "Ashok kumar"Do obj.DefineProperty("test")
	Write obj.PropAccess() ; prints "test"
}

Method PropAccess() [ Language = python ] {

return self.Name }

Method DefineProperty(name) [ Language = python ] {

self.Name = name }

2.  Parameters

Get the parameter arbitrary key value pair by using the _GetParameter. Refer the useful community post 

ClassMethod GetParam(parameter = "MYPARAM") [ Language = python ]
{
	import iris
	value = iris.cls(__name__)._GetParameter(parameter)
	print(value)
}

3. La méthode de classe et les méthodes

3.1 La méthode de classe

L'invocation des méthodes et des fonctions de classe est très utile pour l'exécution du code de script d'objet.

Il est possible d'invoquer la méthode de classe en tant qu'appel statique,  par exemple: Do ..Test() 

ClassMethod InvokeStaticClassMethods(clsName = "MyLearn.EmbeddedPython") [ Language = python ]
{
	import iris
	print(iris.cls(clsName).Test())
	# print(iris.cls(__name__).Test()) 
}


Invocation de la méthode de Classe au moment de l'exécution Set method="Test" Do $ClassMethod(class, method, args...)

ClassMethod InvokeClassMethodsRunTime(classMethod As %String = "Test") [ Language = python ]
{
 import iris
 clsMethodRef = getattr(iris.cls(__name__), classMethod) # renvoie la référence de la méthode
 print(clsMethodRef()) 
}

3.2  Méthodes

Invocation des méthodes d'instance est identique au format "script d'objet". Dans le code ci-dessous, j'ai d'abord créé l'objet, puis j'ai appelé la méthode d'instance avec des paramètres.

ClassMethod InvokeInstanceMethodWithActualParameters() [ Language = python ]
{
	import iris
	obj = iris.cls(__name__)._New()
	print(obj.TestMethod(1,2,4))
}

3.3  Transmission d'arguments par valeur et  par référence entre python et ObjectScript

Fondamentalement, la transmission des arguments est  inévitable entre les fonctions et elle en sera de même entre ObjectScript et Python

3.4  Transmission d'arguments par valeur - C'est comme d'habitude la transmission d'arguments par valeur

ClassMethod passbyvalfromCOStoPY()
{
    Set name = "test", dob= "12/2/2002", city="chennai"Do..pypassbyvalfromCOStoPY(name, dob, city)
}

ClassMethod pypassbyvalfromCOStoPY(name As%String, dob As%String, city As%String) [ Language = python ] { print(name,' ',dob,' ',city) }

/// transmission par valeur de python au script d'objetClassMethod pypassbyvalfromPY2COS() [ Language = python ] { import iris name = 'test' dob='12/2/2002' city='chennai' iris.cls(name).passbyvalfromPY2COS(name, dob, city) }

ClassMethod passbyvalfromPY2COS(name As%String, dob As%String, city As%String) { zwrite name,dob,city }

3.5 Transmission par référence- C'est au contraire de la transmission par valeur. Comme Python ne supporte pas nativement l'appel par référence, il faut donc utiliser la fonction iris.ref()  dans le code Python pour que la variable devienne une référence. à savoir, la référence . A ma connaissance, il n'y a pas d'effets du côté du script d'objet concernant les variables de type pass-by-reference (transmission par référence), même lorsque ces variables sont modifiées en Python. Par conséquent, les variables Python seront affectées par ce mécanisme de pass-by-reference lorsque les méthodes du script d'objet seront invoquées

ClassMethod pypassbyReffromPY2COS() [ Language = python ]
{
	import iris
	name='python'
	dob=iris.ref('01/01/1991')
	city = iris.ref('chennai')
	print('before COS ',name,'  ',dob.value,'  ',city.value)
	#transmission par référence de la date de naissance, ville
	iris.cls('MyLearn.EmbeddedPythonUtils').passbyReffromPY2COS(name, dob, city)	
	print('after COS ',name,'  ',dob.value,'  ',city.value)
}

ClassMethod passbyReffromPY2COS(name, ByRef dob, ByRef city) { Set name="object script", dob="12/12/2012", city="miami" }

// résultat LEARNING>do##class(MyLearn.EmbeddedPythonUtils).pypassbyReffromPY2COS() before COS python 01/01/1991 chennai after COS python 12/12/2012 miami


3.5 **kwargs- Il existe un support supplémentaire pour passer les arguments de mot-clé python (**kwargs) à partir d'un script d'objet. InterSystems IRIS n'ayant pas de concept d'arguments de mot-clé, il faut créer un  %DynamicObject pour contenir les paires mot-clé/valeur et passer les valeurs en tant qu' Args...de syntax

J'ai créé le dynamicObject "name""ashok""city""chennai"}et j'y ai inséré les paires clé-valeur requises, que j'ai ensuite transmises au code python.

ClassMethod KWArgs()
{
    set kwargs={ "name": "ashok", "city": "chennai"}
    do..pyKWArgs(kwargs...)
}

ClassMethod pyKWArgs(name, city, dob = "") [ Language = python ] { print(name, city, dob) }

// résultat LEARNING>do##class(MyLearn.EmbeddedPythonUtils).KWArgs() ashok chennai

Je décrirai les globales, les routines et SQL dans le prochain article

0
0 63
Article Iryna Mykhailova · Oct 28, 2024 2m read

Les fonctions d'agrégation définies par l'utilisateur sont prises en charge dans IRIS depuis 2021.1.0. J'avais souhaité une étoile pour celle-ci il y a des années avant de trouver un moyen secret et astucieux de remplacer MAX et MIN dans un type de données personnalisé, mais je n'ai pas eu l'occasion d'en essayer un jusqu'à aujourd'hui. J'ai pensé que c'était une expérience/un exemple intéressant - la question de savoir comment obtenir une médiane dans IRIS SQL s'est déjà posée une fois - donc je la partage ici sans trop de commentaires supplémentaires.

0
0 37
Article Ben Spead · Oct 24, 2024 15m read

Vous ne le réalisez peut-être pas, mais votre compte de connexion InterSystems peut être utilisé pour accéder à un très large éventail de services InterSystems pour vous aider à apprendre et à utiliser Intersystems IRIS et d'autres technologies InterSystems plus efficacement.  Poursuivez votre lecture pour en savoir plus sur la manière de découvrir de nouvelles connaissances techniques et de nouveaux outils grâce à votre compte de connexion InterSystems.  Après votre lecture, veuillez participer au sondage en bas de page, afin que nous puissions voir dans quelle mesure cet article vous a été utile!

Qu'est-ce qu'un compte de connexion InterSystems? 

Le compte de connexion InterSystems est utilisé pour accéder à divers services en ligne destinés aux clients potentiels, aux partenaires et aux utilisateurs d'InterSystems.  Il s'agit d'un ensemble unique d'informations d'identification utilisées dans plus de 15 applications externes.  Certaines applications (comme WRC ou iService) nécessitent une activation spécifique pour que l'accès soit accordé par le compte.  Il est probable qu'il existe des ressources qui vous aideront mais dont vous ne connaissiez pas l'existence - assurez-vous de lire toutes les options et d'essayer un nouvel outil pour vous aider à améliorer votre niveau technique!!

Catalogue d'Applications

Vous pouvez consulter tous les services disponibles avec votre compte de connexion InterSystems en visitant le Catalogue d'applications d'InterSystems, situé à l'adresse suivante:  https://Login.InterSystems.com.  Ce catalogue ne répertorie que les applications ou services auxquels vous avez actuellement l'accès.  Il se souvient de vos applications les plus fréquemment utilisées et les place en tête de liste pour vous faciliter la tâche. 

N'oubliez pas de marquer la page d'un signet pour accéder facilement à tous ces outils dans la boîte à outils de votre compte de connexion InterSystems!

Détails de l'application 

Il est maintenant temps d'entrer dans les détails des applications individuelles et de voir comment elles peuvent vous aider en tant que développeur travaillant avec les technologies d'InterSystems!  Lisez la suite et essayez de trouver une nouvelle application à utiliser pour la première fois afin d'améliorer votre efficacité et vos compétences en tant que développeur....

 Getting Started (Pour Commencer) - gettingstarted.intersystems.com 

Audience

  • Toute personne souhaitant explorer l'utilisation de la plateforme de données InterSystems IRIS®

Description

  • Avec InterSystems IRIS, vous apprendrez à développer rapidement des applications critiques à forte intensité de données.
  • Les vidéos et les tutoriels permettent de travailler en utilisant SQL, Java, C#/.Net, Node.js, Python ou InterSystems ObjectScript.
  • Pour travailler sur les tutoriels, utilisez un bac à sable gratuit, basé sur le cloud et intégré au navigateur : IRIS+IDE+Web Terminal. 

Comment cela aide à améliorer votre niveau technique

  • Vous vous orientez rapidement vers la technologie d'InterSystems et vous la voyez en action avec des exemples et du code de travail réels!
  • Vous pouvez explorer l'utilisation d'autres langages de programmation populaires avec InterSystems IRIS.

 Apprentissage en ligne - learning.intersystems.com

Audience

  • Tous les utilisateurs actuels et potentiels qui utilisent les solutions d'InterSystems 

Description

  • Des documents autodidactes pour développer et prendre en charge les applications les plus importantes au monde:
    • Exercices pratiques
    • Vidéos
    • Cours en Ligne
    • Parcours d'apprentissage

Comment cela aide à améliorer votre niveau technique

  • Apprenez, apprenez, apprenez!! 
  • Rien ne vous permettra de devenir un développeur plus efficace plus rapidement que de suivre un formateur technique compétent qui vous guidera à travers de nouveaux concepts à utiliser dans vos projets InterSystems IRIS! 

 Documentation - docs.intersystems.com 

Audience

  • Tous les utilisateurs actuels et potentiels qui utilisent les solutions d'InterSystems

Description

  • Documentation pour toutes les versions de nos produits
  • Liens vers la documentation externe si nécessaire
  • Tout le contenu récent est alimenté par notre nouveau moteur de recherche.
  • La page de recherche vous permet de filtrer par produit, version, et autres facettes.
  • Certaines documentations nécessitent une autorisation (via le compte de connexion InterSystems):
    • Les documents AtScale sont disponibles pour les utilisateurs d'Adaptive Analytics
    • Les documents HealthShare sont disponibles pour les utilisateurs de HealthShare
  • Assurez-vous d'utiliser la nouvelle dynamique de liste de contrôle de l'impact des mises à niveau Upgrade Impact Checklist dans le serveur Docs!

Comment cela aide à améliorer votre niveau technique

  • Utilisation rapide du matériel de référence en classe et la documentation de l'API.
  • Recherche de l'exemple de code. 
  • Il est possible de lire une documentation d'utilisation détaillée pour les sections d'InterSystems IRIS dans lesquelles vous souhaitez approfondir vos connaissances.
  • Il est possible de demander des précisions supplémentaires ou de signaler des problèmes directement à partir des pages de documentation grâce à la fonctionnalité "Feedback".

 Évaluation - evaluation.intersystems.com

Audience

  • Les utilisateurs qui souhaitent télécharger des logiciels ou des licences d'InterSystems à des fins d'évaluation ou de développement

Description

  • Téléchargement d'InterSystems IRIS et d'InterSystems IRIS for Health.
  • Tout le monde peut télécharger des kits d'Édition communautaire.
  • Les utilisateurs existants peuvent également demander une licence puissante pour évaluer les fonctionnalités d'entreprise.
  • Des versions préliminaires sont disponibles avant la publication.
  • Les paquets du programme d'accès anticipé permettent de fournir un retour d'information sur les futurs produits et fonctionnalités.

Comment cela aide à améliorer votre niveau technique

  • Il est possible d'essayer les versions d'aperçu des logiciels pour voir comment les nouvelles fonctionnalités peuvent aider à accélérer votre développement.
  • Il est possible de tester les fonctionnalités d'Enterprise en demandant une licence d'évaluation.
  • Vous pouvez vous assurer que tous les développeurs de votre organisation ont la dernière version d'InterSystems IRIS installée sur leurs machines.
  • Vous pouvez fournir des commentaires à InterSystems Product Management sur les fonctionnalités Early Access afin de vous assurer qu'elles répondront aux besoins de votre équipe une fois qu'elles seront entièrement disponibles.

 Communauté de développeurs - community.intersystems.com

Audience

  • Tous ceux qui travaillent avec la technologie d'InterSystems (employés, utilisateurs, partenaires et clients potentiels d'InterSystems)

Description

  • Suivi des annonces relatives aux produits et services d'InterSystems.
  • Recherche d'articles sur une variété de sujets techniques.
  • Questions et réponses de la part de la communauté.
  • Découverte des offres d'emploi ou des développeurs disponibles à l'embauche.
  • Participation à des concours dotés de prix en espèces d'une valeur de 1 000 dollars.
  • Toujours être au courant de ce qui se passe chez InterSystems!

Comment cela aide à améliorer votre niveau technique

  • Grâce à l'accès aux principaux experts mondiaux de la technologie InterSystems, vous pouvez apprendre auprès des meilleurs et rester engagé face aux questions, tendances et sujets les plus brûlants.
  • Réception automatique dans votre boîte de réception de mises à jour sur les nouveaux produits, les nouvelles versions et les opportunités du Programme d'accès anticipé.
  • Vous pouvez obtenir l'aide de vos collègues pour répondre à vos questions et surmonter les obstacles.
  • Vous pouvez avoir des discussions enrichissantes avec les chefs de produits et les développeurs de produits d'InterSystems - apprenez à la source!
  • Vous pouvez améliorer vos compétences en partageant des solutions techniques et du code et en profitant du retour d'information de vos collègues.

 Idées InterSystems - ideas.intersystems.com

Audience

  • Tous ceux qui souhaitent partager des idées pour améliorer la technologie d'InterSystems.

Description

  • Publication d'idées sur la façon d'améliorer la technologie InterSystems.
  • Découverte des commentaires existants et attribution d'un vote positif ou participation à des discussions.
  • InterSystems prendra en compte les idées les plus populaires pour les futures feuilles de route des produits.

Comment cela aide à améliorer votre niveau technique

  • Vous pouvez voir vos idées et vos besoins transformés en réalité dans les produits d'InterSystems ou dans les bibliothèques open source.
  • Vous pouvez vous familiariser avec les idées de vos collègues et apprendre à utiliser les produits d'InterSystems d'une nouvelle manière.
  • Il est possible de mettre en œuvre des idées suggérées par d'autres, d'explorer de nouvelles parties de la technologie d'InterSystems.

 Les Masters Mondiaux - globalmasters.intersystems.com

Audience

  • Tous ceux qui souhaitent promouvoir la technologie InterSystems et obtenir des badges et des goodies

Description

  • Plate-forme de gamification conçue pour permettre aux développeurs d'apprendre, de rester à jour et d'obtenir la reconnaissance de leurs contributions par le biais d'un contenu interactif.
  • Des points et des badges sont attribués aux utilisateurs pour:
    • Engagement auprès de la Communauté de développeurs
    • Engagement auprès d' Open Exchange
    • Publication de messages sur les médias sociaux concernant les produits et les technologies d'InterSystems
  • Des points peuvent être échangés contre des goodies InterSystems ou de la formation gratuite

Comment cela aide à améliorer votre niveau technique

  • Les défis attirent votre attention sur des articles ou des vidéos que vous avez peut-être manqués sur la communauté de développeurs, le site d'apprentissage ou la chaîne YouTube - vous apprendrez sans cesse de nouvelles choses à appliquer à vos projets!

 Open Exchange - openexchange.intersystems.com 

Audience

  • Les développeurs qui cherchent à publier ou à utiliser des progiciels et des outils réutilisables

Description

  • Outils et progiciels pour développeurs conçus avec les plates-formes de données et les produits d'InterSystems. 
  • Les progiciels sont publiés sous diverses licences logicielles (la plupart en open source).
  • Intégration avec GitHub pour la gestion des versions des progiciels, les discussions et la détection des bogues.
  • Il est possible de lire et de soumettre des commentaires et de trouver les progiciels les plus populaires.
  • Les développeurs peuvent soumettre des problèmes et apporter des améliorations aux progiciels via les demandes d'extraction de GitHub pour  aider à faire avancer les logiciels de la communauté.
  • Les développeurs peuvent voir les statistiques de trafic et de téléchargements des progiciels  publiés par eux

Comment cela aide à améliorer votre niveau technique

  • Pas besoin de réinventer la roue!  Utilisez les progiciels open source créés et maintenus par la Communauté de développeurs d'InterSystems pour résoudre des problèmes génériques, ce qui vous permet de vous concentrer sur le développement de solutions spécifiques à votre secteur d'activité.
  • La contribution à des progiciels open source est un excellent moyen de recevoir des commentaires constructifs sur votre travail et d'affiner vos modèles de développement.
  • En devenant un contributeur respecté à des projets open source, il est tout à fait possible de voir la demande augmenter pour vos compétences et vos connaissances. 

 WRC - wrc.intersystems.com

Audience

  • Système de suivi de tous les problèmes signalés par les utilisateurs sur InterSystems IRIS et InterSystems HealthShare.  Les utilisateurs disposant de SUTA peuvent travailler directement avec l'application.

Description

  • Application "Worldwide Response Center" (Centre de réponse mondial, alias "WRC Direct”).
  • Système de suivi des problèmes signalés par les utilisateurs. 
  • Ouverture de nouvelles demandes. 
  • Affichage de toutes les actions d'investigation et ajout de renseignements et de commentaires sur une demande. 
  • Affichage des informations statistiques sur l'historique de vos appels d'assistance. 
  • Clôture des demandes et fourniture d'un retour d'information sur le processus d'assistance. 
  • Examen des fichiers correctifs ad hoc. 
  • Suivi des demandes de modification de logiciel.
  • Téléchargement des versions actuelles du produit et du logiciel client.

Comment cela aide à améliorer votre niveau technique

  • Les techniciens d'InterSystems peuvent vous aider à surmonter les obstacles techniques que vous avez en ce qui concerne le développement ou la gestion des systèmes avec les produits InterSystems.
  • Rapport de bogues pour s'assurer que les problèmes sont corrigés dans des versions ultérieures.  

 iService - iservice.intersystems.com

Audience

  • Les utilisateurs nécessitant une assistance dans le cadre d'un contrat SLA

Description

  • Plateforme de billetterie d'assistance pour nos  utilisateurs des secteurs de la santé, du cloud et les utilisateurs hébergés.
  • Elle permet de calculer la conformité des contrats de niveau de service (SLA) et d'établir des rapports en fonction de règles.
  • La plateforme fournit des fonctionnalités avancées de recherche et d'exportation de facettes. 
  • Elle intègre un système complet de gestion de la sécurité clinique.

Comment cela aide à améliorer votre niveau technique

  • Les techniciens d'InterSystems peuvent vous aider à surmonter les obstacles techniques que vous avez en ce qui concerne le développement ou la gestion des systèmes avec les produits InterSystems pour la santé ou le cloud.
  • Rapport de bogues pour s'assurer que les problèmes sont corrigés dans des versions ultérieures.  

 ICR - containers.intersystems.com

Audience

  • Tous ceux qui souhaitent utiliser les conteneurs InterSystems

Description

  • Registre des conteneurs InterSystems
  • Registre de conteneurs accessible programmé et interface web pour la navigation.
  • Conteneurs de l'édition communautaire sont accessibles à tous.
  • Versions commerciales d'InterSystems IRIS et d'InterSystems IRIS for Health disponibles pour les utilisateurs soutenus.
  • Génération des jetons à utiliser dans les pipelines CICD pour récupérer automatiquement les conteneurs.

Comment cela aide à améliorer votre niveau technique

  • Il est possible d'augmenter la maturité de votre SDLC en passant à des pipelines CICD basés sur des conteneurs pour votre développement, vos tests et votre déploiement!

 Répertoire de partenaires - partner.intersystems.com 

Audience

  • Tous ceux qui cherchent à trouver un partenaire InterSystems ou un produit partenaire 
  • Partenaires cherchant à faire la publicité de leurs logiciels et services  

Description

  • Recherche de tous types de partenaires InterSystems:
    • Partenaires de mise en œuvre
    • Partenaires de solutions
    • Partenaires technologiques
    • Partenaire cloud
  • Les partenaires existants peuvent gérer leurs listes de services et de logiciels. 

Comment cela aide à améliorer votre niveau technique

  • Il est possible de faire appel à des experts certifiés sur une base contractuelle pour apprendre d'eux dans le cadre de vos projets.
  • Vous pouvez acquérir des licences pour des solutions d'entreprise basées sur la technologie InterSystems, ce qui vous évite d'avoir à tout construire à partir de zéro.
  • Vous pouvez apporter vos produits et services à un public plus large, augmentant ainsi la demande et vous obligeant à accroître votre capacité de livraison!

 CCR - ccr.intersystems.com 

Audience

  • Organisations sélectionnées gérant les changements apportés à une implémentation d'InterSystems (employés, partenaires et utilisateurs finaux)

Description

  • Enregistrement de contrôle des modifications
    • Application de flux de travail personnalisée construite sur notre propre technologie pour suivre toutes les personnalisations apportées aux produits de santé InterSystems installés dans le monde entier.
  • Versionnement et déploiement du code personnalisé sur site et des modifications de configuration.
  • Plusieurs niveaux et options de configuration du flux de travail.
  • Adaptation très souple aux besoins spécifiques de la phase du projet

Comment cela aide à améliorer votre niveau technique

  • Pour les équipes autorisées à l'utiliser, il est possible de trouver et de réutiliser du code ou des plans de mise en œuvre au sein de votre organisation, ce qui évite de devoir résoudre le même problème plusieurs fois.
  • Résolution beaucoup plus rapide des problèmes en production, ce qui laisse plus de temps pour le travail de développement. 

 Connexion Client - client.intersystems.com  

Audience

  • Disponible pour tous les clients de TrakCare

Description

  • InterSystems Client Connection est une plateforme de collaboration et de partage des connaissances pour les clients de TrakCare.
  • Cette communauté en ligne permet aux clients de TrakCare d'établir des relations plus nombreuses, plus efficaces et plus étroites.
  • Sur la plateforme de connexion client "Client Connection", les éléments suivants sont disponibles: 
    • Des nouvelles et des événements concernant TrakCare 
    • Des documents de lancement de TrakCare, par exemple des documents de lancement et des vidéos de prévisualisation
    • L'accès aux guides de produits les plus récents.
    • Des supports permettant d'approfondir les connaissances personnelles.
    • Des forums de discussion pour tirer parti de l'expertise des pairs. 

Comment cela aide à améliorer votre niveau technique

  • Les spécialistes techniques et d'application des sites TrakCare peuvent partager rapidement leurs questions et leurs connaissances, en se connectant à d'autres utilisateurs dans le monde entier.  Des réponses plus rapides signifient plus de temps pour élaborer des solutions!

 Commande en ligne - store.intersystems.com

Audience

  • Utilisateurs des opérations chez les partenaires d'application sélectionnés/utilisateurs finaux

Description

  • Possibilité pour les utilisateurs de choisir différents produits en fonction de leurs contrats et de créer de nouvelles commandes.  
  • Possibilité pour les utilisateurs de mettre à niveau ou d'échanger des commandes existantes.
  • Soumission des commandes à InterSystems Customer Operations pour process les traiter en vue de la livraison et de la facturation.
  • Possibilité pour les utilisateurs de migrer les licences existantes vers InterSystems IRIS.

Comment cela aide à améliorer votre niveau technique

  • Honnêtement, en aucune façon!  Il s'agit d'un outil utilisé par le personnel des opérations et non par les utilisateurs techniques, mais il est listé ici par souci d'exhaustivité puisque l'accès est contrôlé via le compte de connexion InterSystems ;)  

Autres choses à savoir sur votre compte de connexion InterSystems

Voici quelques autres informations utiles sur les comptes de connexion InterSystems...

Comment créer un compte de connexion

Les utilisateurs peuvent créer leur propre compte en cliquant sur "Créer un compte" sur n'importe quelle application publique d'InterSystems, y compris:

Par ailleurs, le FRC (First Response Center) d'InterSystems créera un compte de connexion pour les utilisateurs supportés la première fois qu'ils auront besoin d'accéder au Worldwide Response Center (WRC) ou à iService (ou les utilisateurs supportés peuvent également créer des comptes pour leurs collègues).

Avant d'utiliser un compte, l'utilisateur doit accepter les conditions générales, soit au cours de la procédure d'auto-enregistrement, soit lors de la première connexion.

Autres options de connexion

Certaines applications permettent de se connecter avec Google ou GitHub:

Il s'agit du même compte de connexion InterSystems, mais avec une authentification par Google ou GitHub.

Profil du compte

Si vous allez à https://Login.InterSystems.com et que vous vous authentifiez, vous pourrez accéder à la rubrique Options > Profil et apporter des modifications de base à votre compte.  L'adresse électronique peut être modifiée via Options > Change Email.  

Résolution des problèmes liés aux comptes de connexion

Les problèmes liés aux comptes de connexion InterSystems doivent être adressés à Support@InterSystems.com.  Veuillez inclure:

  • Nom d'utilisateur utilisé pour le login tenté
  • Adresse électronique
  • Type et version du navigateur
  • Messages d'erreur spécifiques et/ou captures d'écran
  • L'heure et la date à laquelle l'erreur a été reçue   
0
0 64