0. Introducción
Si estamos en Linux solo podremos hacer ejecutables windows si utilizamos Wine, pero suele fallar.
Para ello es conveniente utilizar Windows para realizar ejecutables Windows y Linux para hacer ejecutables Linux.
Lo primero que hay que hacer es instalar pyinstaller
# En windows
pip install pyinstaller
# En windows si falla
python -m pip install pyinstaller
# En Linux
./bin/python -m pip install pyinstaller
1. Caso especial de windows 11
Cuando se instala en windows 11 se instala pyinstaller dentro de la carpeta del usuario. Por tanto debemos incluir en el path del usuario
En windows tenemos que añadir a las variables de entorno de usuario estas carpetas tal como se muestra:
C:\Users\eduard\AppData\Local\Programs\Python\Python312\Scripts
C:\Users\eduard\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\Scripts
2. Generación del ejecutable
Ahora ejecutamos la opción para que genere un único fichero (en este caso hemos utilizado el módulo python mdph.py
# En windows
Pyinstaller --onefile -w mdph.py
# En windows, si falla
python -m Pyinstaller --onefile -w mdph.py
# En Linux
pyinstaller --onefile mdph.py
Ahora ejecutamos la opción para que genere un único fichero
Para el caso de linux, crea una carpeta llamada dist y dentro está el ejecutable mdph
3. Ejemplo de conversión
Anteriormente hemos utilizado el comando de creación del ejecutable del módulo mdph.py. Ahora vamos a mostrar el detalle de este fichero y el módulo adicional que utiliza.
El problema en cuestión consiste en transformar un fichero excel que por cada persona tiene 4 filas, donde hay un campo "Denominació" que puede tomar los valores "Observacions, pares, emails y telefons", y otro campo "Valor" que toma los valores específicos". El fichero transformado tendrá un único registro por persona y le añadirá los 4 campos Observacions, pares, emails y telefons"
Para este ejemplo tenemos que instalar las dependencias pandas, numpy y tkinter
# En windows
pip install pandas
pip install numpy
pip install tkinter
# En Linux
./bin/python -m pip install pandas
./bin/python -m pip install numpy
./bin/python -m pip install tkinter
Y utilizamos 2 módulos mdexcel.py y mdph.py
El primero (mdexcel.py) tiene utilidades para manejar ficheros excel
El segundo (mdph.py)
3.1 mdexcel.py
import pandas
import numpy
def getExcel(object)->object:
excel=pandas.read_excel(object)
return excel
def getCSVText(object)->str:
myStr=""
excel=pandas.ExcelFile(object)
for sheetName in excel.sheet_names:
sheet=pandas.read_excel(excel, sheetName)
myStr+=str(sheet)
print (myStr)
return myStr
#getCSVText("/home/eduard/Baixades/edu.xlsx")
def getColumnNamesAndRows(obj:object, sheetName:str='')->list[list[object]]:
excel=pandas.ExcelFile(obj)
print (excel)
colNames=[]
if len(sheetName)==0:
sheet=pandas.read_excel(excel, excel.sheet_names[0])
else:
sheet=pandas.read_excel(excel, excel.sheet_names[excel.sheet_names.index(sheetName)])
for column in sheet.columns:
print (column)
colNames.append(column)
return colNames,sheet.values
def getColumnValues(columnNames:list[str], values:list[list[object]], wantedCols:list[str])->list[object]:
allCols=[]
for colName in wantedCols:
print('colName='+colName)
myCol=[]
colNum=columnNames.index(colName)
for row in values:
myValue=row[colNum]
myCol.append(myValue)
allCols.append(myCol)
return allCols
def list2ExcelFile(inList:list[list[object]], filePath:str, transpose:bool=False):
df=None
if transpose:
print('Transposing the matrix and getting dataframe........')
df=pandas.DataFrame(numpy.array(inList).T)
else:
print('Getting dataframe........')
df=pandas.DataFrame(inList)
with pandas.ExcelWriter(filePath) as writer:
print ('Writing excel File.....')
df.to_excel(writer, sheet_name='Full1')
import mdexcel
import tkinter
import tkinter.filedialog
#-------------------------------------------------------------------
# Arreglem el xls que torna el programa del padró que conté fins
# 4 registres per persona amb cada línia té:
# pares, observacions, teléfons i emails
# I afegeix eixos 4 camps i deixa només una línia per persona
#-------------------------------------------------------------------
def arreglarXLS(input:object, outFilePath:str)->object:
print('1. Reading Excel File...')
columnNames,myData= mdexcel.getColumnNamesAndRows(input)
myWantedCols=['Nº documento','Nom' ,'Partícula 1' ,'Cognom 1' ,'Partícula 2',
'Cognom 2' ,'Data naixement','Cognoms i Nom','Tipus Via normalitzat','Nom Via',
'Nombres' ,'Escala' ,'Codi Planta' ,'Porta' ,'Nom nucli/disseminat (50)',
'Adreça' ,"Data d'alta" ,'Denominació' ,'Valor' ,'Estat']
myColNames= myWantedCols[0:17] + ['Emails','Observacions','Telefons', 'PARES'] + myWantedCols[19:20]
print('2. getting column Values...')
myDataCols=mdexcel.getColumnValues(columnNames, myData, myWantedCols)
print('3. Selecting data...')
myDocu='xxxx',
myCognomNom='xxxxx'
#Create a list of columns
myNewDataCols=[]
#add column headers
for name in myColNames:
aList=[]
aList.append(name)
myNewDataCols.append(aList)
ii=0
for i in range(len(myDataCols[0])):
if myDataCols[0][i]!=myDocu or myDataCols[7][i]!=myCognomNom:
myDocu= myDataCols[0][i]
myCognomNom=myDataCols[7][i]
ii+=1
for j in range(len(myColNames)):
myNewDataCols[ j].append('')
if j<17 : myNewDataCols[ j][ii]=myDataCols[j][i]
if j>=17 and j<21: myNewDataCols[ j][ii]=''
if j==21: myNewDataCols[ j][ii]=myDataCols[19][i]
if myDataCols[17][i]==myColNames[17]: myNewDataCols[17][ii]=myDataCols[18][i]
if myDataCols[17][i]==myColNames[18]: myNewDataCols[18][ii]=myDataCols[18][i]
if myDataCols[17][i]==myColNames[19]: myNewDataCols[19][ii]=myDataCols[18][i]
if myDataCols[17][i]==myColNames[20]: myNewDataCols[20][ii]=myDataCols[18][i]
print('4. Writing excel file...')
mdexcel.list2ExcelFile(myNewDataCols,outFilePath, transpose=True)
print('5. The end ...')
return True
def getOutputFileName(inputFileName:str)->str:
if inputFileName.endswith('.xlsx'):
return inputFileName.replace('.xlsx','.arreglat.xlsx')
else: import mdexcel
import tkinter
#-------------------------------------------------------------------
# Arreglem el xls que torna el programa del padró que conté fins
# 4 registres per persona amb cada línia té:
# pares, observacions, teléfons i emails
# I afegeix eixos 4 camps i deixa només una línia per persona
#-------------------------------------------------------------------
def arreglarXLS(input:object, outFilePath:str)->object:
print('1. Reading Excel File...')
columnNames,myData= mdexcel.getColumnNamesAndRows(input)
myWantedCols=['Nº documento','Nom' ,'Partícula 1' ,'Cognom 1' ,'Partícula 2',
'Cognom 2' ,'Data naixement','Cognoms i Nom','Tipus Via normalitzat','Nom Via',
'Nombres' ,'Escala' ,'Codi Planta' ,'Porta' ,'Nom nucli/disseminat (50)',
'Adreça' ,"Data d'alta" ,'Denominació' ,'Valor' ,'Estat']
myColNames= myWantedCols[0:17] + ['Emails','Observacions','Telefons', 'PARES'] + myWantedCols[19:20]
print('2. getting column Values...')
myDataCols=mdexcel.getColumnValues(columnNames, myData, myWantedCols)
print('3. Selecting data...')
myDocu='xxxx',
myCognomNom='xxxxx'
#Create a list of columns
myNewDataCols=[]
#add column headers
for name in myColNames:
aList=[]
aList.append(name)
myNewDataCols.append(aList)
ii=0
for i in range(len(myDataCols[0])):
if myDataCols[0][i]!=myDocu or myDataCols[7][i]!=myCognomNom:
myDocu= myDataCols[0][i]
myCognomNom=myDataCols[7][i]
ii+=1
for j in range(len(myColNames)):
myNewDataCols[ j].append('')
if j<17 : myNewDataCols[ j][ii]=myDataCols[j][i]
if j>=17 and j<21: myNewDataCols[ j][ii]=''
if j==21: myNewDataCols[ j][ii]=myDataCols[19][i]
if myDataCols[17][i]==myColNames[17]: myNewDataCols[17][ii]=myDataCols[18][i]
if myDataCols[17][i]==myColNames[18]: myNewDataCols[18][ii]=myDataCols[18][i]
if myDataCols[17][i]==myColNames[19]: myNewDataCols[19][ii]=myDataCols[18][i]
if myDataCols[17][i]==myColNames[20]: myNewDataCols[20][ii]=myDataCols[18][i]
print('4. Writing excel file...')
mdexcel.list2ExcelFile(myNewDataCols,outFilePath, transpose=True)
print('5. The end ...')
return True
def getOutputFileName(inputFileName:str)->str:
if inputFileName.endswith('.xlsx'):
return inputFileName.replace('.xlsx','.arreglat.xlsx')
else:
return inputFileName.replace('.xls','.arreglat.xls')
def capturaExcel(inputFileNameEntry):
fitxerExcel=tkinter.filedialog.askopenfilename( filetypes=[("Excel files", ".xlsx .xls")])
inputFileNameEntry.delete(0,tkinter.END)
inputFileNameEntry.insert(0,fitxerExcel)
def arreglarExcel(inputFileNameEntry):
# Get the user input from the form
inputFileName = inputFileNameEntry.get()
outputFileName=getOutputFileName(inputFileName)
arreglarXLS(inputFileName, outputFileName)
tkinter.messagebox.showinfo("Success", "Proces acabat!")
def formArreglarXLS():
# Create the main tkinter window
root = tkinter.Tk()
root.title("Arreglar fitxer Excel per a importar a ODOO")
root.geometry('800x300')
# Create labels and entry fields for each input
#inputFileNameLabel= tkinter.Label(root, text="A capturar....:").grid(row=0, sticky=tkinter.W)
inputFileNameLabel= tkinter.Label(root, text="Fitxer:")
inputFileNameLabel.grid(row=0, column=0)
#inputFileNameLabel.pack()
inputFileNameEntry= tkinter.Entry(root, text='', width=70)
inputFileNameEntry.grid(row=0, column=1)
#inputFileNameEntry.pack()
#botoCaptura = tkinter.Button(root, text ="Capturar Fitxer excel del padró", command = capturaExcel(inputFileNameEntry))
botoCaptura = tkinter.Button(root, text ="Capturar", command = lambda:capturaExcel(inputFileNameEntry))
botoCaptura.grid(row=0, column=2)
#botoCaptura.pack()
#executeButton = tkinter.Button(root, text="Arreglar Excel del Padró", command=arreglarExcel(inputFileNameEntry))
executeButton = tkinter.Button(root, text="Arreglar Excel del Padró", command=lambda:arreglarExcel(inputFileNameEntry))
executeButton.grid(row=5, column=1)
#executeButton.pack()
executeButton.grid()
root.mainloop()
''''
------------------------------------------------------------
Tests
------------------------------------------------------------
'''
def mytest():
#if __name__ == '__main__':
#props=mdconfig.read_app_props("sqlite")
'''
inDir='/home/eduard/MyOdoo/Control-Presencia/DADES/'
inFName='Padro_habitants_migracio_sedipualba240416.xlsx'
outFName=inFName.replace('.xls','.out.xls')
arreglarXLS(inDir+inFName, inDir+outFName)
'''
formArreglarXLS()
#------ main
mytest()