Last Updated on 8 Dicembre 2019 by Roberto De Pedrini
Ieri sera ricevo una mail con una richiesta di un cliente: “Ho alcuni programmi che generano dei file PDF in determinate cartelle IFS: avrei la necessità di fare una procedura che unisca i PDF in uno solo. Ho trovato qualcosa fatto in Java cercando su Google ma la classe Java va in errore. Sai come risolvere o conosci qualche alternativa?”.
Premetto che non ho mai imparato a programmare in Java ed ho un certo rifiuto verso le cose Java … sono molto più attratto dai nuovi linguaggi tipo Python o anche Node.js e quindi faccio due ricerche su Google e mi si apre un mondo!
Essendo passata una sola settimana dall’ultimo evento Faq400 “Hands-on Open Source & Modernization tools” dello scorso 26 Novembre approfitto per affrontare la richiesta del cliente utilizzando proprio il “nuovo mondo” Open Source che si apre a IBM i con Python, Node.js ecc
Cerco su Google e trovo PYPDF2 un tools Python per estrarre dati dai PDF, gestire, modificare e creare PDF con Python… ottimo … scelgo Python … non ho grandissime esperienze con questo linguaggio ma è questione solo di iniziare ad usarlo.
E’ Sabato mattina … sto aspettando il sole per fare una corsa con moglie e cane, ho circa un’ora di tempo prima che si alzi il sole. Avete mai corso nel bosco nelle fredde mettine d’Autunno quando il primo sole scioglie velocemente la brina notturna? Ne vale la pena! Non ci crederete ma è’ più bello che scrivere codice in Python o RPG.
La brina ci racconta i mille istanti della notte che si sono cristallizzati.
(Fabrizio Caramagna)
Ho un’ora di tempo, il cane inizia ad agitarsi perché mi vede vestito per la corsa (e non è un bel vedere, la pancetta da programmatore viene ancora più evidenziata dalla maglia gialla Decathlon e i pantaloni da corsa attillati… ma al cane non importa e vuole andare!).
Devo installare Python sull’IBM i del cliente, scaricare PyPDF2, testare il tutto e fare un CL per richiamarlo dalle “normali” applicazioni del cliente.
Ok, si può fare!
Premessa: I source di questo post sono disponibili su GitHub
I sorgenti di questo post sono disponibili in questo progetto Github pubblico: https://github.com/Faq400Git/IFS_PDFUnion
Eccovi passo passo la cronistoria del lavoro che vede l’attivazione di SSH, l’installazione delle basi ACS per Open Source, l’installazione di Python e dei tools per lavorare con i PDF … quasi un gioco da ragazzi. Vediamolo:
(1) Start Server SSHD e impostazione per Autostart
Appena tento di collegarmi alla partizione IBM i con la gestione dei Pacchetti Open Source di ACS incontro subito un piccolo problema: non è avviato il server SSHD e per l’Open Source è un prerequisito. Lo faccio partire subito con il comando STRTCPSVR:
STRTCPSVR SERVER(*SSHD)
Visto che SSH può sempre servire e l’IBM i si riavvia tutte le domeniche preferisco impostare il daemon SSHD in Autostart: Apro Navigator for i facendo partire dal link di ACS e vado ad impostare l’autostart del server SSHD:
- Avvio Navigator for i
- Scelgo Rete – Server – Server TCP
- Seleziono SSHD
- Da azioni vado in “Proprietà”
- Setto “Avvio all’avvio di TCP/IP” (ma perché non lasciano scritto Autostart in inglese, mannaggia!)
(2) Open Source Package Manager di ACS Access Client Solution
Non avendo mai installato il Package Manager per l’Open Source di ACS … mi viene proposto di installarlo … lo faccio seguendo le istruzioni chiari di ACS, una procedura molto semplice se si è ad un buon livello di sistema operativo IBM i (diciamo dalla 7.2 in avanti!).
(3) Installazione di Python3
Finalmente posso installare Python3 … operazione molto semplice con la gestione dei Pacchetti Open Source di ACS, è sufficiente eseguire l’azione “Open Source Package Management”, scegliere la scheda “Available Packages”, seleziona Python3 e Install.
Faccio la stessa cosa con il pacchetto python3-pip che mi servità per installare i package Python (in questo caso specifico PyPDF2).
Ringrazio IBM per aver finalmente adottato RPG e YUM per la gestione dei pacchetti Open Source: il vecchio prodotto 5733OPS era sì molto simile agli altri LICPGM di IBM ma non si prestava affatto al mondo dell’Open Source dove ci sono continui aggiornamenti e ogni giorno escono nuove cose interessanti.
Grazie al laboratorio gestito da Jesse Gorzinski per il suo ottimo lavoro!
I pacchetti Open Source installati con questa interfaccia vengono depositati nella cartella “/QOpenSys/pkgs/bin” … generalmente non raggiungibile con la path di default degli utenti SSH: per poter richiamare Python3 o altri Open Source installati in questo modo conviene aggiungere alla path dell’utente quella cartella e lo si può fare solo per la sessione attuale con queste due istruzioni
PATH=/QOpenSys/pkgs/bin:$PATH export PATH
Oppure inserire queste due righe direttamente nel .profile dell’utente ( ~/.profile … generalmente qualcosa del tipo /home/mysuser/.profile). Se non dovesse esistere possiamo crearlo (nel seguente caso utilizzo vi da ambiente SSH ma potremmo utilizzare EDTF da ambiente IBMi
vi ~/.profile quindi inseriamo le due righe PATH=/QOpenSys/pkgs/bin:$PATH export PATH oppure da ambiente IBM i edtf '/home/myUser/.profile'
(4) Accesso con Putty SSH e installazione del tools PYPDF2 per la gestione dei PDF con Python
Proseguo con l’installazione del pacchetto PyPDF2 per la gestione dei PDF con Python utilizzando PIP3, il Package Manager di Python:
- Mi collego con SSH
- Creo una cartella /home/openSource
- Entro nella cartella /home/openSource
- installo PyPDF2 tramite il comando PIP3 install
- Ho appena installato Python3-pip e già mi segnala che dovrei aggiornare anche “pip” … faccio anche questo aggiornamento.
bash cd /home mkdir openSource cd openSource pip3 install PyPDF2 pip3 install --upgrade pip
(5) Script Python e test del Merge-Append di due PDF in uno solo
Recupero da Google un esempio di utilizzo PyPDF2 per eseguire Split and Merge di PDF e scrivo il mio piccolo script Python con qualche modifica … un gioco da ragazzi… carico due pdf qualsiasi dal mio pc in una cartella IFS di test e provo il programma… qualche aggiustamento ma in poco tempo funziona tutto.
Ecco lo script Python (disponibile su Github https://github.com/Faq400Git/IFS_PDFUnion , copiatelo da lì)
# pdfUnion.py # Here how to use this script # python3 /home/openSource/pdfUnion.py /home/openSource/pdfUnion/test/ outputfile.pdf PDFNR1.pdf PDFNR2.pdf # Some import (like /copy and /include in RPG) import sys import os import PyPDF2 merger = PyPDF2.PdfFileMerger() # Here are my input parms path = sys.argv[1] out_file = sys.argv[2] in_files = sys.argv[3:] # Una lista di PDF dal terzo parm in avanti # Set the path for input and output files os.chdir(path) # Loop into in_files (two or more files) for pdf in in_files: try: #if doc exist then merge if os.path.exists(pdf): input = PyPDF2.PdfFileReader(open(pdf,'rb')) merger.append((input)) else: print(f"problem with file {pdf}")except:
print("cant merge !! sorry")
else:
print(f" {pdf} Merged !!! ")
# write output file on disk merger.write(out_file) # end
Provo a richiamare lo script dandogli in pasto i due PDF appena caricati ed ottengo un outfile.pdf che è esattamente l’union dei due!
python3 /home/openSource/pdfUnion.py /home/openSource/pdfUnion/test/ outputfile.pdf PDFNR1.pdf PDFNR2.pdf
(6) Preparo un CL per richiamare lo script Python … che lascerò al cliente da chiamare dalle sue applicazioni
Ecco invece il CLP che richiama lo script Python via Qshell (anche questo source è disponibile su Github https://github.com/Faq400Git/IFS_PDFUnion … copiatelo da lì che non ci sono problemi di conversione caratteri come sui post di WordPress!)
/* --------------------------------------------- */ /* pdfunion(path outfile infile1 infile2) */ /* Chiama uno script python per l'unione di due pdf */ /* in una determinata cartella IFS passata nel parametro path */ /* --------------------------------------------- */ PGM PARM(&path &outfile &infile1 &infile2)DCL VAR(&path) TYPE(*CHAR) LEN(030)
DCL VAR(&outfile) TYPE(*CHAR) LEN(030)
DCL VAR(&infile1) TYPE(*CHAR) LEN(030)
DCL VAR(&infile2) TYPE(*CHAR) LEN(030)
DCL var(&cmd) type(*char) len(256)
/* Create call command */ CHGVAR VAR(&CMD) VALUE('/QOpenSys/pkgs/bin/python3' *BCAT + '/home/openSource/pdfunion/pdfUnion.py' *BCAT %TRIM(&PATH) *BCAT + %TRIM(&OUTFILE) *BCAT %TRIM(&INFILE1) *BCAT %TRIM(&INFILE2)) /* Call Python script */ QSH CMD(&cmd)ENDPGM
Provo a chiamare il mio CL
call pdfunion parm('/home/openSource/pdfunion/test' 'outfile2.pdf' 'PDFNR1.pdf' 'PDFNR2.pdf')
Funziona al primo colpo … grande!
Conclusione
Vi assicuro che ho perso molto più tempo a scrivere il post, metterlo su Github, sistemarlo e documentarlo rispetto al tempo impiegato per ottenere il risultato voluto dal cliente.
Il progetto è naturalmente migliorabile… fa il suo lavoro ma non ha una gestione degli errori corretta … andrebbe gestito qualche messaggio d’errore dallo script Python per poi intercettarlo nello Standard Output dal CL ( QIBM_QSH_CMD_OUTPUT o altre strade).
Quello che va assolutamente detto è che il mondo dell’Open Source su IBM i apre mille strade per risolvere problemi di questo tipo…. bisogna solo iniziare a lavorarci.
E tu cosa stai facendo? Hai provato a fare qualcosa con l’Open Source?
Posso finalmente uscire a correre con moglie, cane e la mia maglietta gialla che evidenzia la pancia … metto la foto da dietro così non si vede!
--- Roberto De Pedrini Faq400.com
Tutto molto, molto interessante.
Sto cercando di installare il pacchetto matplotlib (qui dicono che si può fare https://www.ibmsystemsmag.com/Power-Systems/11/2019/How-to-Start-ml-on-IBM-i) per poter pubblicare qualche grafico partendo dal db2, ma l’installazione dà un sacco di problemi. Tu ci hai mai provato?
Non sono sicuro che fosse Matplotlib ma ho visto qualcosa di interessante fatto da Andrea Ribuoli (https://www.linkedin.com/in/andrea-ribuoli-5b37403b/),nostro Blogger e Speaker degli eventi Faq400 …
Potresti provare a contattere lui che sull’Open Source ha un sacco di cose da dire …
Ciao a tutti. Personalmente come interfaccia tra il mondo RPG/iseries ed il richiamo ad uno script Python uso la libreria PYONI, che potete trovare qui : https://github.com/richardschoen/PythonOniLibrary.
Poi nel mio caso ho personalizzato uno dei due comandi lì già pronti per poter ricevere lo stdout in una variabile. Infine per mia comodità ho mappato il richiamo ai vari script in procedure racchiuse a loro volta in un service program.
Altre cose che ho trovato utili col Python sono la decodifica/codifica in base 64 (si usa l’import base 64). La cancellazione di un file contenuto nel IFS. Ed il consumo di web services attraverso il pycurl, che và installato sempre col pip come visto sopra. Infine ibm_db per la connessione da Python al database As400.
Saluti Antonio.