Cool 😀
Merci pour le message de confirmation.
- Se connecter pour publier des commentaires
Cool 😀
Merci pour le message de confirmation.
Bonjour @Cyril Grosjean
essaie d'utiliser embedded python, en remplaçant la connexion par create_engine('iris+emb:///'):
from sqlalchemy import create_engine
_engine = create_engine('iris+emb:///')Bonjour @Cyril Grosjean
essaie d'utiliser embedded python, en remplaçant la connexion par create_engine('iris+emb:///'):
from sqlalchemy import create_engine
_engine = create_engine('iris+emb:///')
Bonjour @Cyril Grosjean
l'erreur indique un "accès refusé".
Peux-tu donner plus d'information sur le code du BP PostFusionIntervention ?
Bonjour @Cyril Grosjean
le pb vient peut-être des librairies python requises qui n'ont pas été correctement installées sur l'environnement WIndows.
Tu peux essayer de le résoudre en installant les librairies python sur Windows via la commande irispip
C:\InterSystems\IRIS\bin>irispip install --target C:\InterSystems\IRIS\mgr\python iris-pex-embedded-pythonBonjour @Pierre LaFay
pour rediriger la sortie standard du Terminal IRIS, tu peux ouvrir un fichier et l'indiquer via la commande USE
Exemple ci-dessous et en ligne :
Class utils.file
{
Parameter DIRECTORY = "/data/";
Parameter FILENAME = "results";
Parameter EXTENSION = ".txt";
/// Redirect standard output to a file
ClassMethod results() As %Status
{
set sc = $$$OK
SET file=..#DIRECTORY _ ..#FILENAME _ "_" _ $tr($zdt($h,8)," :")_..#EXTENSION
OPEN file:("NRW"):5
USE file
WRITE !,"BEGIN RESULTS ",$zdt($h,3),!
do ##class(UnitTest.utils).run("Test3")
WRITE !,"END RESULTS ",$zdt($h,3)
CLOSE file
WRITE !,"Results are in ",file,!
return sc
}
}
.png)
Avec le fichier contenant toutes les écritures vers la sortie :.png)
Merci @Iryna Mykhailova et @Brett Saviano
Cela est très utile en effet et fonctionne aussi avec IRIS 2023.3 sans Private Web Server (depuis IRIS 2023.2)
.png)
La commande alias est aussi très pratique et souvent méconnue :
.png)
Hello @Pierre LaFay
tu peux aussi utiliser la commande "!" sans paramètre pour ouvrir une session du système d'exploitation et revenir au terminal IRIS en quittant la session de l'OS.
Exemple ci-dessous :
.png)
Merci @Pierre LaFay et @Seisuke Nakahashi pour cet article intéressant, qui apporte une autre méthode d'exploitation des rapports de performances.
Je vous invite à essayer également YASPE (Yet Another System Performance Extractor), qui génére des rapports html par une exploitation des rapports en Python.
merci @Vadim Aniskin pour ce retour.
Bonjour @Jean-Charles Cano,
pour en savoir plus sur les logs, côté IRIS tu peux activer les traces dans les paramètres du Business Service :.png)
En t'assurant que les traces sont aussi activées au niveau des paramètres de la production :.png)
Ajouté au portail des idées InterSystems
Réponse d' @Eduard Lebedyuk :
L'approche la plus sûre consiste à utiliser Privileged Routine Application.
Bonjour @Jean-Charles Cano,
les messages commençant par "ConfigItem" font simplement partie des messages d'information dans le journal des événements indiquant le démarrage d'un service/process/operation dans la production (en précisant l'ID du processus de la tâche associée).
D'après tes captures d'écran, cela signifie que la connexion a échoué le 27/12 à 04:25 et que le service a correctement redémarré (message ConfigItem), le 28/12 à 14:45, ainsi que le même jour à 14:50, 16:27, etc.
Peut-être que le pb vient du paramètre Rester connecté (StayConnected) = -1 .png)
Le passer à une valeur positive ou à 0 règlera peut-être le pb.
Et @Vitaliy Serdtsev conclue :
Ajout à ce qui précède : pagination SQL accélérée
@Eduard Lebedyuk précise :
L'idée d'un ensemble de résultats défilants est d'appeler Save/OpenId - et l'ensemble de résultats continuera automatiquement sur une ligne suivante. Vous n'avez donc pas besoin de gérer les indices avant/arrière :
Un exemple ici
C'est également environ 3 fois plus rapide puisque la requête n'est exécutée qu'une seule fois :
do ##class(User.Pagination).Time("Save")
Save took 0,0048 sec
do ##class(User.Pagination).Time("NoSave")
NoSave took 0,0143 sec@Guillaume Rongier ajoute :
Bonjour Rubén,
Une autre proposition sur IRIS 2021.1+ peut être celle-ci avec l'utilisation de la fonction nouvelle fenêtre (OVER) :
ClassMethod getPersonsPagWindow(iAge As %Integer, sortField As %String = 1, sortOrder As %String = 2, pageSize As %String = 20, pageIndex As %String = 1) As %DynamicObject
{
set out = []
set vFrom = ((pageIndex -1 ) * pageSize)+1
set vTo = vFrom + (pageSize-1)
set sql = "SELECT * "_
"FROM ( SELECT persons.* "_
" , ROW_NUMBER() OVER (ORDER By "_sortField_" "_ $CASE(sortOrder,1:"ASC",2:"DESC",:"ASC")_
" ) rn "_
" FROM Sample.Person persons where Age > ? "_
" ) tmp "_
"WHERE rn between "_vFrom_" and "_vTo_" "_
"ORDER By "_sortField_" "_ $CASE(sortOrder,1:"ASC",2:"DESC",:"ASC")
Set rs=##class(%ResultSet).%New("%DynamicQuery:SQL")
set sc = rs.Prepare(sql)
set sc = rs.Execute(iAge) If $$$ISERR(sc) Do DisplayError^%apiOBJ(sc) Quit
while rs.%Next() {
Do out.%Push({
"pid": (rs.%Get("ID")),
"ssn" : (rs.%Get("SSN")),
"lastname" : (rs.%Get("LastName")) ,
"givenname": (rs.%Get("GivenName")),
"secondaryname": (rs.%Get("SecondaryName")) ,
"gender": (rs.%Get("Gender")),
"age": (rs.%Get("Age") )
})
}
set outJson = []
Do outJson.%Push({
"pageSize":(pageSize),
"pageIndex":(pageIndex),
"fromIndex":(vFrom),
"toIndex":(vTo),
"resultSet":(out)
})
return outJson
}Je compare les deux solutions sur un dataset de 100 000 lignes sans index avec un résultat de 20 éléments en page 1 et voici les résultats :
"getPersonsPag timed : 1,647 secondes"
"getPersonsPagWindow timed : 0,247 secondes"Je suppose que la fonction window est plus rapide car vous n'avez pas besoin de récupérer toutes les données de manière globale avant la pagination.
Une fois obtenu le fichier Excel, il est possible de le convertir en CSV puis en PDF en utilisant les librairies pandas et csv2pdf
ClassMethod toPDF(file As %String) As %Status [ Language = python ]
{
import pandas as pd
from csv2pdf import convert
PATH = '/home/irisowner/dev/data/'
PATH_TO_XLSX = PATH+file+'.xlsx'
PATH_TO_CSV = PATH+file+'.csv'
PATH_TO_PDF = PATH+file+'.pdf'
read_file = pd.read_excel (PATH_TO_XLSX)
read_file.to_csv (PATH_TO_CSV, index = None, header=True)
convert(PATH_TO_CSV , PATH_TO_PDF)
}Bonjour @Pierre LaFay
en m'inspirant des liens proposés par @Guillaume Rongier tu trouveras ci-dessous et en ligne un exemple de génération de feuille Excel à partir de openpyxl
Code
/// d ##class(apptools.python.xlsx).test()
Class apptools.python.xlsx
{
Parameter DATADIRECTORY = "/home/irisowner/dev/data/";
/// d ##class(apptools.python.xlsx).test()
ClassMethod test(name As %String = "titanicTest") As %Status
{
set name=name_$INCREMENT(^RunAppTest(name))
set sql="select * FROM dc_demo.titanic"
#; set sql="select name,sex,age FROM dc_demo.titanic"
set gn="^||tmp",format=",n,n,n,n,s5,s5,s40,s5,s50"
set format("freeze")="B3" ;freeze
set format("title")="Title "_sql
set format("sheetname")="test"
#; do ##class(apptools.core.sys).SaveSQL(sql,gn)
set exec="##class(apptools.python.xlsx).MarkRed(.%AppLogInfoVal, .%AppLogInfoCol, .%AppLogInfoHead, .%AppLogInfoTemp)"
#; do ##class(apptools.python.xlsx).gn2xlsx(gn,.format,..#DATADIRECTORY_"___gn2xlsx*.xlsx","Title "_sql,,,,exec)
set format("freeze")="B4" ;freeze
do ##class(apptools.python.xlsx).sql2xlsx(sql,.format,..#DATADIRECTORY_name_".xlsx")
do ..toPDF(name)
return $$$OK
}
ClassMethod sql2xlsx(sql, format = "", file As %String = "/home/irisowner/dev/data/sample-py-*.xlsx", title = "")
{
set st=$$$OK
set statement = ##CLASS(%SQL.Statement).%New()
set status=statement.%Prepare(sql)
if $$$ISERR(status) {write "%Prepare failed:" do $SYSTEM.Status.DisplayError(status) quit}
set rset=statement.%Execute()
if (rset.%SQLCODE '= 0) {write "%Execute failed:", !, "SQLCODE ", rset.%SQLCODE, ": ", rset.%Message quit}
;prepare XLSX
try {
set openpyxl = ##class(%SYS.Python).Import("openpyxl")
} catch err {
do ..InstallPy("openpyxl")
set openpyxl = ##class(%SYS.Python).Import("openpyxl")
}
set wb = openpyxl.Workbook()
#; grab the active worksheet
set ws = wb.active
set ws.title = $select($D(format("sheetname"),ds):ds,1:"sheetname")
set pybuiltins = $system.Python.Import("builtins")
set pycols = pybuiltins.list()
do pycols.append(" ")
do ws.append(pycols)
set pycols = pybuiltins.list()
set (count)=0
set ColCount=statement.%Metadata.columns.Count()
for i=1:1:ColCount {
do pycols.append(statement.%Metadata.columns.GetAt(i).colName)
set col=openpyxl.utils."get_column_letter"(i)
}
do ws.append(pycols)
while (rset.%Next()) {
set count=count+1
set pyrows = pybuiltins.list()
for ii=1:1:ColCount {
set val=..CleanCtrl(rset.%GetData(ii))
if $e($P(format,",",ii),1)="d" { //date
set val=..ToPyDate(val)
}
elseif $e($P(format,",",ii),1,2)="dt" { //datetime
set val=..ToPyDateTime(val)
}
elseif $e($P(format,",",ii),1)="n" { //number
set val=+val
}
do pyrows.append(val)
}
do ws.append(pyrows)
}
;}
if $g(format("freeze"))'="" {
; set builtins = $system.Python.Import("builtins") zwrite builtins.type(ws) zwrite builtins.dir(wb)
set ws."freeze_panes" = pybuiltins.str(format("freeze")) ;format("freeze")
;set ws."freeze_panes" = "B2" ;format("freeze")
}
else {
set ws."freeze_panes" = pybuiltins.str("B2") ;default
}
if file["*" set file=$replace(file,"*","-"_$zd($h,3)_"_"_$tr($zt($p($h,",",2),1),":"))
write !,"Save into "_file_" rows: "_count
do wb.save(file)
return $GET(count)
}
ClassMethod toPDF(file As %String) As %Status [ Language = python ]
{
import pandas as pd
from csv2pdf import convert
PATH = '/home/irisowner/dev/data/'
PATH_TO_XLSX = PATH+file+'.xlsx'
PATH_TO_CSV = PATH+file+'.csv'
PATH_TO_PDF = PATH+file+'.pdf'
read_file = pd.read_excel (PATH_TO_XLSX)
read_file.to_csv (PATH_TO_CSV, index = None, header=True)
convert(PATH_TO_CSV , PATH_TO_PDF)
}
/// set gn="^||tmp",format="n,s150,,,,,,,,d,"
/// set format("freeze")="B5" ;freeze
/// d ##class(apptools.core.sys).SaveSQL("select * from apptools_core.Log order by id desc",gn)
/// d ##class(apptools.python.xlsx).gn2xlsx(gn,.format,"/iris-backup/temp/test*.xlsx","Test")
/// Example coloring a column values if is not null
/// set exec="##class(apptools.python.xlsx).MarkRed(.%AppLogInfoVal, %AppLogInfoCol, %AppLogInfoHead, .%AppLogInfoTemp)"
ClassMethod MarkRed(Val, Col, Head, openpyxl)
{
s res=Val
if $g(Head) {
if res.value="DispatchClass" set Col("DispatchClass",Col)=""
}
else {
if $Data(Col("DispatchClass",Col)) {
if res.value'="" {
;set argsfill = {"start_color":"D3D3D3", "end_color":"D3D3D3", "fill_type":"solid"}
;set fill = openpyxl.styles.PatternFill(argsfill...)
set argsfont = {"color":"DC143C", "bold":true, "italic":false, "size":11} ;color Crimson
set font = openpyxl.styles.Font(argsfont...)
;set res.value=$FN(res.value,"",2)
;set res.fill=fill
set res.font=font
}
}
}
q res
}
/// do ##class(apptools.python.xlsx).InstallPy("openpyxl")
ClassMethod InstallPy(lib)
{
// depricated ;set sc = ##class(%SYS.Python).Install("openpyxl")
set cmd="pip3 install --target /usr/irissys/mgr/python/ "_lib
if $zversion(1)'=3 {
set tMgrDir = $System.Util.ManagerDirectory()
set tBinDir = $System.Util.BinaryDirectory()_"irispip.exe"
set cmd=tBinDir_" install --target "_tMgrDir_"python "_lib
}
set st=##class(%ZPM.PackageManager.Developer.Utils).RunCommandViaZF(cmd,.tLog,.tErr)
quit $$$OK
}
/// Date YYYY-MM-DD HH:MM:SS to Python dt.datetime
ClassMethod ToPyDateTime(val, ByRef dt)
{
quit:'val val
if val["." set val=$p(val,".",3)_"-"_$p(val,".",2)_"-"_$p(val,".",1) // format YYYY-MM-DD
if val'["-" set val=$zd(+val,3) // $h format
set dt = ##class(%SYS.Python).Import("datetime")
set val=dt.datetime(+$p(val,"-",1), +$p(val,"-",2), +$p($p(val,"-",3)," "),+$p($p(val,":",1)," ",2),+$p($p(val,":",2)," ",2),+$p($p(val,":",3)," ",2))
quit val
}
/// Date YYYY-MM-DD to Python dt.date
ClassMethod ToPyDate(val, ByRef dt)
{
quit:'val val
if val["." set val=$p(val,".",3)_"-"_$p(val,".",2)_"-"_$p(val,".",1) // format YYYY-MM-DD
if val'["-" w 111_val_111 set val=$zd(+val,3) // $h format
set dt = ##class(%SYS.Python).Import("datetime")
set val=dt.date(+$p(val,"-",1), +$p(val,"-",2), +$p($p(val,"-",3)," "))
quit val
}
ClassMethod CleanCtrl(val)
{
quit $zstrip(val,"*C")
}
}
2023 a été une très belle année pour Developer Community, qui a vu le nombre de ses membres s'accroître fortement, dans toutes ses pays, avec une augmentation de la qualité des articles, des commentaires et des applications sur Open Exchange.
2024 sera encore plus riche en contenus et en solutions
Exemple de classe utilisant un index IDKEY
Test
IRISAPP>w ##class(data.centre).test()
^data.centreD("departement",83)=10
^data.centreD("departement",83,1)=$lb("","The industry leader in just-in-time seven-sigma Internet content for social networks.")
^data.centreD("departement",83,2)=$lb("","On-line distributors of open distributed Internet connectivity for capital markets.")
^data.centreD("departement",83,3)=$lb("","Developers of cutting-edge HTML5 XML instruments for our long-term clients.")
^data.centreD("departement",83,4)=$lb("","Building shareholder value by delivering advanced financial application development media for industry and academia.")
^data.centreD("departement",83,5)=$lb("","Providers of breakthrough satellite-based advanced connectivity for industry and academia.")
^data.centreD("departement",83,6)=$lb("","Resellers of cloud-based seven-sigma database connectivity for the enterprise.")
^data.centreD("departement",83,7)=$lb("","Developers of dynamic object-oriented graphical services for social networks.")
^data.centreD("departement",83,8)=$lb("","Developers of high-performance nano-advanced productivity tools for the Fortune 50.")
^data.centreD("departement",83,9)=$lb("","Specializing in the development and manufacturing of breakthrough wireless forecasting marketing services for the enterprise.")
^data.centreD("departement",83,10)=$lb("","Enabling individuals and businesses to manage just-in-time big data Internet technologies for discriminating investors.")
1
IRISAPP>w ##class(data.centre).test(3)
^data.centreD("departement",83)=13
^data.centreD("departement",83,1)=$lb("","The industry leader in just-in-time seven-sigma Internet content for social networks.")
^data.centreD("departement",83,2)=$lb("","On-line distributors of open distributed Internet connectivity for capital markets.")
^data.centreD("departement",83,3)=$lb("","Developers of cutting-edge HTML5 XML instruments for our long-term clients.")
^data.centreD("departement",83,4)=$lb("","Building shareholder value by delivering advanced financial application development media for industry and academia.")
^data.centreD("departement",83,5)=$lb("","Providers of breakthrough satellite-based advanced connectivity for industry and academia.")
^data.centreD("departement",83,6)=$lb("","Resellers of cloud-based seven-sigma database connectivity for the enterprise.")
^data.centreD("departement",83,7)=$lb("","Developers of dynamic object-oriented graphical services for social networks.")
^data.centreD("departement",83,8)=$lb("","Developers of high-performance nano-advanced productivity tools for the Fortune 50.")
^data.centreD("departement",83,9)=$lb("","Specializing in the development and manufacturing of breakthrough wireless forecasting marketing services for the enterprise.")
^data.centreD("departement",83,10)=$lb("","Enabling individuals and businesses to manage just-in-time big data Internet technologies for discriminating investors.")
^data.centreD("departement",83,11)=$lb("","On-line distributors of scalable predictive analytic XML gaming for our long-term clients.")
^data.centreD("departement",83,12)=$lb("","On-line distributors of interactive quantum advanced media for the pharmaceutical industry.")
^data.centreD("departement",83,13)=$lb("","Building shareholder value by delivering innovative distributed cold-fusion powered gaming for the Financial community.")
1Class data.centre Extends %Persistent
{
/// Description
Index IdKeyIndex On (APP, DD, NNN) [ IdKey ];
/// Nom de l'application utilisée par le centre
Property APP As %String;
/// n° du département du centre
Property DD As %Integer;
/// n° séquentiel dans le département
Property NNN As %Integer;
Property description As %String(MAXLEN = "");
ClassMethod create(APP As %String, DD As %Integer, description As %String) As %Status
{
set a = ..%New()
set a.APP = APP
set a.DD = DD
set a.NNN = $INCREMENT(^data.centreD(APP,DD))
set a.description = description
set sc = a.%Save()
return sc
}
ClassMethod test(nb As %Integer = 10) As %Status
{
for i=1:1:nb {
set sc = ..create("departement",83,##class(%PopulateUtils).Mission())
}
zw ^data.centreD
return sc
}
Storage Default
{
<Data name="centreDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>description</Value>
</Value>
</Data>
<DataLocation>^data.centreD</DataLocation>
<DefaultData>centreDefaultData</DefaultData>
<IdLocation>^data.centreD</IdLocation>
<IndexLocation>^data.centreI</IndexLocation>
<StreamLocation>^data.centreS</StreamLocation>
<Type>%Storage.Persistent</Type>
}
}
Dans ton cas, $INCREMENT te donnera une meilleure garantie de séquentialité, en évitant les sauts de numéros.
Bonjour @Pierre LaFay
tu peux aussi utiliser $SEQUENCE
$SEQUENCE est spécifiquement destiné aux opérations d'incrémentation d'entiers impliquant plusieurs processus simultanés.
NB: si tu rencontres d'autres erreurs, pense à les indiquer clairement dans les échanges afin qu'elles soient référencées ; cela permet de les retrouver plus facilement lors des recherches de pb similaires déjà rencontrés.
Bonjour Moussa,
comme vu ensemble cet après-midi, je t'invite à bien tracer chaque étape et à consulter cet échange autour de l'authentication OAuth 2.0 avec Microsoft Office 365.
Bien à toi,
Sylvain
C'est effectivement un très beau premier jalon @Irène Mykhailova
Merci de partager cette très encourageante information.
à suivre 😍
Bonjour @Jean-Charles Cano,
Stream n'est pas une méthode mais une propriété ; aussi, tout devrait aller mieux après avoir remplacé cette ligne :
set esc = ..Adapter.PutStream(fileName, pRequest.Stream())par celle-ci :
set esc = ..Adapter.PutStream(fileName, pRequest.Stream)Je suis bien d'accord @Iryna Mykhailova
Le site InterSystems Learning étant déjà disponible en français, peut-être verrons-nous prochainement des contenus de plus en plus nombreux de formations dans la langue de Molière et de Prévert.
Réponse de @Ashok Kumar T
Bonjour @Muhammad Waseem
Vous pouvez peut-être essayer d'extraire la ressource patient du bundle ou l'utiliser si c'est déjà une ressource. Chargez la classe du modèle patient FHIR HS.FHIR.DTL.vR4.Model.Resource.Patient avec la ressource extraite. Ensuite, vous pouvez convertir la date de naissance et valider l'âge. Vous pouvez utiliser la même logique dans votre code DTL dans un processus FHIR entre le service FHIR (HS.FHIRServer.Interop.Service) et l'opération FHIR (HS.FHIRServer.Interop.Operation).
ClassMethod VaidatePatientResource(patientResourceStreram As %Stream.Object)
{
#dim patient As HS.FHIR.DTL.vR4.Model.Resource.Patient
try {
set patient = ##class(HS.FHIR.DTL.vR4.Model.Resource.Patient).FromJSON(patientResourceStreram)
Set age = $horolog - $ZdateH(patient.birthDate,3)\360
if age<18 $$$ThrowStatus($$$ERROR($$$GeneralError, "Age is less than 18"))
}
catch ex {
w ex.DisplayString()
}
}