2

I am using pyinstaller to turn a script into an exe file so I can give it to people who don't have python and other packages installed. Its just a simple script that uses pandas and numpy to manipulate excel sheets. I found that I can run the exe using the base conda env but not outside of it. I have followed the fixes found at PyInstaller .exe file terminates early without an error message but the issue is still present. I don't know what you guys need from me to help answer the question so let me know and I will edit this entry.

My Code:

import pandas as pd
import numpy as np
import openpyxl

print('Starting Operations')

#Load the file
spend_report = pd.read_excel('Spend Report_Console.xlsx',converters={'Document\nCompany': str,'Document\nNumber':str})
print('Data Loaded')


#Load the exchange rate file
fx_rates = pd.read_excel('FX_Rates.xlsx')
#Create a new index for the dataframe. This will allow much faster accessing of the data
fx_rates['index'] = fx_rates['Date'].dt.strftime('%b-%y')
fx_rates.index=fx_rates['index']
fx_rates.drop(['Date','index'],axis=1,inplace=True)
print('FX Rates Loaded')


company_currency = {'00002':'EUR','00003':'EUR','00004':'GBP','00005':'CRC','00006':'RMB','00008':'RMB'}
# If 00001, keep the same


#Drop any row where the Supplier\nNumber does not start with a number
#Make a new column, that indicates this
spend_report['to_keep'] = spend_report['Supplier\nNumber'].apply(lambda x: x[0].isdigit())
spend_report.drop(spend_report[spend_report['to_keep']==False].index,axis=0,inplace=True)
spend_report.drop(['to_keep'],axis=1,inplace=True)

#FillNA's in Purchase Order and Order Type
spend_report.fillna({'Purchase Order':'','Order Type':''},inplace=True)


#Correct Document Company
#Logic:
# If Document Company is 00000:
    # Replace with f'0000{First number of Document Number}'
def fix_docCompany(company,number):
    if company == '00000':
        return f'0000{number[0]}'
    return company  

spend_report['Document\nCompany'] = spend_report.apply(lambda row: fix_docCompany(row['Document\nCompany'],row['Document\nNumber']),axis=1)
print('Fixing Document Company')


#Correct the currency
#Logic:
# If company is not 00001:
    # Get value from company_currency
# return same value
def fix_currency(company,currency):
    if company != '00001':
        return company_currency[company]
    return currency

spend_report['Currency'] = spend_report.apply(lambda row: fix_currency(row['Document\nCompany'],row['Currency']),axis=1)
print('Fixing Currency')


#Check for missing currency
currencies = pd.unique(spend_report['Currency'])
missing = [curr for curr in currencies if curr not in fx_rates.columns]
if len(missing) > 0:
    print(f'The following currencies are missing:\n{missing}\nThere will be an error thrown.')
    t = input('Press enter to acknowledge.')

# Calculate the USD amount
def usd_amount(date, currency, amount):
    return amount / fx_rates.loc[date,currency]

spend_report['USD Amount'] = spend_report.apply(lambda row: usd_amount(row['GL Date'].strftime('%b-%y'),
                                                                       row['Currency'],row['Gross\nAmount']),axis=1)
print('Calculating USD Amount')


#Create the PO/NON-PO column
spend_report['PO/NON-PO']=np.where(spend_report['Purchase Order']=='','NON-PO','PO')
print('Creating PO/NON-PO Column')


#Write to excel after rearranging columns
print('Writing to Excel')
with pd.ExcelWriter(f'Spend Report_Output.xlsx',datetime_format='m/dd/yyyy',engine='openpyxl') as writer:
    spend_report[['Supplier\nNumber','Document\nType','Document\nNumber',
                  'Document\nCompany','Pay Item','Invoice Date','GL Date',
                  'Due Date','Pay\nStatus','Gross\nAmount','Open\nAmount',
                  'Currency','USD Amount','Batch\nType','Batch\nNumber',
                  'Batch\nDate','Purchase Order','Order Type','PO/NON-PO']].to_excel(writer,sheet_name='SpendReport',index=False)
    fx_rates.to_excel(writer,sheet_name='FX_Rate')

print('Operations Complete')

My Conda Env was created by using the following commands:

conda create -n make python=3.9
conda activate make
conda install numpy
conda install pandas
conda install openpyxl
conda install pyinstaller

I had to modify the spec file since I ran into the Intel MKL Fatal Error issue. I created the file using the function:

pyinstaller -F Spend_Report.spec

When I run it in the (base) and the (make) environments it works fine.

(base) C:\Users\**\**\Spend Report>Spend_Report.exe
Starting Operations
Data Loaded
FX Rates Loaded
Fixing Document Company
Fixing Currency
Calculating USD Amount
Creating PO/NON-PO Column
Writing to Excel
Operations Complete
(make) C:\Users\**\**\Spend Report>Spend_Report.exe
Starting Operations
Data Loaded
FX Rates Loaded
Fixing Document Company
Fixing Currency
Calculating USD Amount
Creating PO/NON-PO Column
Writing to Excel
Operations Complete

However, if I close the conda command prompt, open up a regular windows command prompt. The exe does not work and just hangs. I need help since I will be sending this to people who have never coded in their life. They won't have anaconda or python installed on their computers.

Wadser
  • 23
  • 4
  • 1
    Provide at least a minimal definition of a Conda environment (preferably in YAML) you have used but does not work. Additionally, it would be useful to have an example script and the command you use to build the binary. – merv Jul 07 '21 at 19:09
  • @merv I think I have what you needed. Please see above. – Wadser Jul 08 '21 at 21:18
  • so when you run through command line outside of conda. Will the script actually terminate on its own? or does it continue run without ever outputting anything – fthomson Jul 08 '21 at 21:30
  • also unrelated but I would recommend building with --onefile to make it easier to pass off – fthomson Jul 08 '21 at 21:34
  • Thanks for adding that! I don't know the solution, but searching around, there seems to be some nagging issue with PyInstaller struggling with dynamic libraries that link using `@rpath` specifications (rather than absolute paths) which Conda environments heavily rely on. Hopefully, someone more knowledgeable can share their insights. – merv Jul 08 '21 at 21:57
  • I suspect the key issue is that while PyInstaller will statically include the directly referenced libraries, those libraries will themselves rely on others through `@rpath` and PyInstaller does not resolve such recursive dependencies. – merv Jul 08 '21 at 22:01
  • Since I'm not on Windows, I can't troubleshoot, but I made [this chat room](https://chat.stackoverflow.com/rooms/info/234675/q-pyinstaller-standalone) for discussion. – merv Jul 08 '21 at 23:36
  • @fthomson When it run it outside in regular cmd it just hangs for a while, then terminates letting me type a new command in. Nothing is printed to console and the output excel file is not generated. Also -F is the same thing as --onefile. – Wadser Jul 09 '21 at 22:13

0 Answers0