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.
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.
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:
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.
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.
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:
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é.
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.
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.
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:
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.
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:
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:
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.
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:
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:
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.
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:
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:
Avec les tracebacks désactivés:
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.
🐍❤️ 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.
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, !
}
}
}
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.
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
}
}
⚠️ 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.
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.
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é.
Si vous souhaitez générer une erreur personnalisée arbitraire dans un bloc TRY, vous pouvez transmettre une exception avec un throw comme suit. Dans l'exemple suivant, une erreur personnalisée est générée si Stcount est inférieur à 1.
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.
# 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
PythonPath peut être configuré dans le portail de gestion IRIS ou dans un fichier merge/cfg
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) :
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:
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:
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.
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")
}
}
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.
# 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")
}
}
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.
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:
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)
}
}
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)
}
}
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)
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
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
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.
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
}
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:
🔁 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.
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.
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:
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:
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:
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!
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:
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.
À 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!
Banksia Globalest 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.
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&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&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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&cmpntname=GetDocumentsById&source=library&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
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é!
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:
À 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.
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:
Cliquez sur le bouton New et créez une requête HTTP.
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.
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.
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 :
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
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.
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.
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:
Votre informateur aurait pu vous fournir le lieu où l'heure locale était 3:14 PM. Par exemple, Los Angeles, les Bahamas, ou Londres.
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.
Bien que cette simplification soit valable pour de nombreux endroits, il existe malheureusement de nombreuses exceptions à cette règle.
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):
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.
Les fêtes de fin d'année approchent à grands pas et il est temps de s'y préparer ! Rejoignez l'Avènment du Code 2024 avec InterSystems et participez à notre défi ObjectScript !
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.
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])}')
}
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
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 w 123 q ir1 w "running ir1" q add(p1,p2) public{ return p1+p2 } sub(p1,p2) s 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.
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
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()
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.
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)
}
// 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.
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.
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....
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!
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".
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.
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.
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!
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.
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.
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.
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!
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!
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.
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!
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: