Vadym K.
Vadym K.

Reputation: 21

Create standalone Mac OS X applications with Python (external ini file issue)

I have an issue when compiling the standalone application on Mac OS (actually I use macOS Mojave 10.14.4) with some data inside the external ini-file

Tried to compile using py2app.

My main.py

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMessageBox

from decryptwindow import Ui_Dialog  # importing our generated file

import sys
import os

class mywindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(mywindow, self).__init__()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)


    app = QtWidgets.QApplication([])
    application = mywindow()
    application.show()
    sys.exit(app.exec())

My interface file (decryptwindow.py)

# Created by: PyQt5 UI code generator 5.11.3

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QInputDialog, QFileDialog, QListWidget, QMessageBox
from PyQt5.QtCore import pyqtSlot
import os
import configparser

from itertools import filterfalse
from pathlib import Path

import click
import PyPDF2

config = configparser.RawConfigParser()
config.read('config.ini')
path_val = config.get('DEFAULT', 'path')
browsetooltip = config.get('LANGUAGE', 'browsetooltip')
selectbutton = config.get('LANGUAGE', 'selectbutton')

if not os.path.exists(path_val):
    path_val = /Users


class Ui_Dialog(QWidget):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(325, 269)
        self.directory = path_val
        self.BrowsepushButton = QtWidgets.QPushButton(Dialog)
        self.BrowsepushButton.setEnabled(True)
        self.BrowsepushButton.setGeometry(QtCore.QRect(240, 10, 75, 23))
        self.BrowsepushButton.setObjectName("BrowsepushButton")
        self.BrowsepushButton.setToolTip(browsetooltip)
        self.BrowsepushButton.clicked.connect(self.BrowsepushButton_on_click)
        self.fileslistWidget = QtWidgets.QListWidget(Dialog)
        self.fileslistWidget.setGeometry(QtCore.QRect(20, 10, 201, 171))
        self.fileslistWidget.setObjectName("fileslistWidget")
        # fill the fileslistWidget with the files from the folder 
        # The folder is taken from the config.ini
        for file_name in os.listdir(path_val):  
        self.fileslistWidget.addItem(file_name)   
        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "PDF decrypt/Encrypt utility"))
        self.BrowsepushButton.setText(_translate("Dialog", selectbutton))

    def BrowsepushButton_on_click(self):
        # print('BrowsepushButton button clicked')

        self.directory = QtWidgets.QFileDialog.getExistingDirectory(self, "Choose the folder")
        if self.directory:  
            for file_name in os.listdir(self.directory):  
                self.fileslistWidget.addItem(file_name)  
            # update existing value in ini file with the self.directory
                config.set('DEFAULT', 'Path', self.directory)
            # save last selected folder back to config.ini
                with open('config.ini', 'w') as configfile:
                    config.write(configfile)

My ini-file (config.ini)

[DEFAULT]
path = /FM32YO/files

[LANGUAGE]
browsetooltip = Click to Select the folder
selectbutton = Select folder

I expect to have path written into the config.ini file. In fact I have it when I run my application via python3

However I need the standalone application.

So my steps are

1) py2applet --make-setup main.py

""
This is a setup.py script generated by py2applet

Usage:
    python setup.py py2app
"""

from setuptools import setup

APP = ['main.py']
DATA_FILES = ['']
OPTIONS = {}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

2) python3 setup.py py2app

And here we are. I have an app file ready to launch. However once I run it, the unknown terminal error is arising.

I was able to avoid the error only after including config.ini into setup.py, which is in fact not good

So my setup.py now looks like:

""
This is a setup.py script generated by py2applet

Usage:
    python setup.py py2app
"""

from setuptools import setup

APP = ['main.py']
DATA_FILES = ['config.ini']
OPTIONS = {}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

After that the application works fine. But.... since the config.ini is included into the app, it is not writable anymore.

Does anyone have ideas how to solve the problem?

Thank you.

p.s. BTW, on windows (application compiled into exe-file) everything works fine.

Upvotes: 1

Views: 2594

Answers (1)

Natsfan
Natsfan

Reputation: 4847

Try running Platypus to convert your python script to an executable. I've used it and it works well.

Upvotes: 2

Related Questions