accéder à la publication Sylvain Guilbaud · Jan 15 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:///')
accéder à la publication Sylvain Guilbaud · Jan 15 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:///')
accéder à la publication Sylvain Guilbaud · Jan 12 Bonjour @Cyril Grosjean l'erreur indique un "accès refusé". Peux-tu donner plus d'information sur le code du BP PostFusionIntervention ?
accéder à la publication Sylvain Guilbaud · Jan 12 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-python
accéder à la publication Sylvain Guilbaud · Jan 12 Bonjour @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 } } Avec le fichier contenant toutes les écritures vers la sortie :
accéder à la publication Sylvain Guilbaud · Jan 12 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)
accéder à la publication Sylvain Guilbaud · Jan 12 La commande alias est aussi très pratique et souvent méconnue :
accéder à la publication Sylvain Guilbaud · Jan 12 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 :
accéder à la publication Sylvain Guilbaud · Jan 11 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.
accéder à la publication Sylvain Guilbaud · Jan 8 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 : En t'assurant que les traces sont aussi activées au niveau des paramètres de la production :
accéder à la publication Sylvain Guilbaud · Jan 5 Réponse d' @Eduard Lebedyuk : L'approche la plus sûre consiste à utiliser Privileged Routine Application.
accéder à la publication Sylvain Guilbaud · Jan 5 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 Le passer à une valeur positive ou à 0 règlera peut-être le pb.
accéder à la publication Sylvain Guilbaud · Jan 2 Et @Vitaliy Serdtsev conclue : Ajout à ce qui précède : pagination SQL accélérée
accéder à la publication Sylvain Guilbaud · Jan 2 @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 Class User.Pagination { /// do ##class(User.Pagination).Time("NoSave") /// do ##class(User.Pagination).Time("Save") ClassMethod Time(method = "Save") { set start = $zh do $classmethod(,method) set end = $zh write $$$FormatText("%1 took %2 sec", method, $fnumber(end-start,"",4)) } /// do ##class(User.Pagination).NoSave() ClassMethod NoSave() { do { do $i(i) set obj = ..getPersonsPage(20,i) //w obj.%ToJSON(),!,! } while (obj.toIndex < obj.resultSetTotal) } /// do ##class(User.Pagination).Save() ClassMethod Save() { do { set obj = ..getPersonsPageSave(20,.id) //w obj.%ToJSON(),!,! } while (id'=-1) } ClassMethod getPersonsPage(pageSize As %String = 20, pageIndex As %String = 1) As %DynamicObject { #dim sc As %Status = $$$OK #dim rs As %ScrollableResultSet set sc = ..getRS(,.rs) quit:$$$ISERR(sc) {"msg": ($System.Status.GetErrorText(sc))} set vFrom = ((pageIndex -1 ) * pageSize) set vTo = vFrom + (pageSize-1) do rs.CurrRowSet(vFrom) set results = [] set:(pageSize >= rs.Count()) pageSize = rs.Count() set i = 0 while rs.%Next() && $i(i) { quit:(i>pageSize) do results.%Push({ "index": (i), "pid": (rs.%Get("ID")), "ssn" : (rs.%Get("SSN")), "age": (rs.%Get("Age"))}) //do results.%Push(+rs.%Get("ID")) } set out = { "pageSize":(pageSize), "pageIndex":(pageIndex), "fromIndex":(vFrom + 1), "toIndex":(vFrom+i), "resultSetTotal":(rs.Count()), "pageRecords":(i), "pages":($NORMALIZE((rs.Count()/pageSize),0)), "resultSet":(results) } return out } ClassMethod getRS(id As %Integer, Output rs As %ScrollableResultSet) As %Status { #dim sc As %Status = $$$OK if '$d(id) { set sql = "SELECT ID, SSN, Age FROM Sample.Person" set rs=##class(%ScrollableResultSet).%New("%DynamicQuery:SQL") set sc = rs.Prepare(sql) quit:$$$ISERR(sc) sc set sc = rs.Execute() quit:$$$ISERR(sc) sc quit:(rs.Count()=0) $$$ERROR($$$GeneralError, "No results") } else { set rs=##class(%ScrollableResultSet).%OpenId(id) } quit sc } ClassMethod getPersonsPageSave(pageSize As %String = 20, ByRef id As %Integer) As %DynamicObject { #dim sc As %Status = $$$OK #dim rs As %ScrollableResultSet set sc = ..getRS(.id,.rs) quit:$$$ISERR(sc) {"msg": ($System.Status.GetErrorText(sc))} set results = [] set:(pageSize >= rs.Count()) pageSize = rs.Count() set i = 0 set notAtEnd = rs.%Next() while notAtEnd && $i(i) { do results.%Push({ "index": (i), "pid": (rs.%Get("ID")), "ssn" : (rs.%Get("SSN")), "age": (rs.%Get("Age"))}) //do results.%Push(+rs.%Get("ID")) quit:(i>=pageSize) set notAtEnd = rs.%Next() } if notAtEnd { do rs.%Save() Set id=rs.%Id() } else { do rs.%DeleteId(id) set id = -1 } set out = { "pageSize":(pageSize), "resultSetTotal":(rs.Count()), "pageRecords":(i), "pages":($NORMALIZE((rs.Count()/pageSize),0)), "resultSet":(results) } kill rs return out } } 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
accéder à la publication Sylvain Guilbaud · Jan 2 @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.
accéder à la publication Sylvain Guilbaud · Déc 27, 2023 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) }
accéder à la publication Sylvain Guilbaud · Déc 27, 2023 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") } }
accéder à la publication Sylvain Guilbaud · Déc 27, 2023 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