03 - Open Source03d - Python

Merge (append) diversi PDF in uno solo (Python on i)

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!

Related Posts
DB2 for i SQL – Stringhe – POSSTR-LOCATE-LOCATE_IN_STRING (IT)

Introduzione Spesso, nelle nostre applicazioni, abbiamo la necessità di lavorare con le stringhe di testo e l'SQL del DB2 può Read more

DB2 for i & SQL – FAQ & Howto (Part. 1) (IT)

Database DB2 e SQL ... forse lo strumento più potente e completo che abbiamo sulla piattaforma IBM i: ecco una Read more

Annuncio IBM i 7.4

Arriva direttamente con l'uovo di Pasqua questo annuncio IBM per le novità della versione IBM i 7.4, versione iNext secondo Read more

Generated Always Columns – Approfondimenti (IT)

Introduzione "Generated Always Column": sono colonne, campi, di una tabella il cui contenuto è controllato direttamente dal sistema ... e Read more

--- Roberto De Pedrini Faq400.com
About author

Founder di Faq400 Srl, IBM Champion, ideatore del sito Faq400.com e del Blog blog.faq400.com. Sviluppatore RPG da quando avevo i pantaloni corti, forte sostenitore della piattaforma IBM i (ex AS400), ho sempre cercato di convididere le mie conoscenze con gli altri tramite forum, eventi e corsi. Oggi, tramite Faq400 Srl, cerchiamo di aiutare le aziende a sfruttare al meglio questa fantastica piattaforma IBM i.

3 Comments

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *