mac.App mit py2app oder PyInstaller erstellen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

hallo gemeinsam,

bin ein absoluter Anfänger in Sachen Programmierung, das ganze wissen habe ich aus dem Google.

habe bzw. bin noch dabei eine App zu schreiben. Doch bevor es Fertig ist wollte erst mal testen, ob es überhaupt realisierbar ist, was ich mir ausgedacht habe.

Kurz zur der App:
Mit dem Programm möchte ich meine Arbeitsstunden(für die Firma) schreiben, als Excel und PDF speichern und dann per Email an meinen Vorgesetzten schicken.

Das Programm möchte ich in Zukunft auch meinen Kollegen geben können( ich selber nutze MacOSX, Aber alle anderen wahrscheinlich Windows).

Zu meinem Problem:
Ich habe bis jetzt nur die GUI erstellt mit PyQt5.
Und in PyCharm funktioniert alles wunderbar.
Jetzt wollte ich probehalber eine App erstellen, leider ohne Erfolg.
Habe py2app und PyInstaller probiert. Das App wird erstellt, aber beim öffnen kommt Error.

Mein Python Code besteht aus mehreren Files.
Start.py( hier wird eine Datei version.txt ausgelesen und anschliessend eine Klasse MainWindow aus MainWindow.py importiert)
MainWindow.py ( hier wird eine Klasse Settings aus Settingspy importiert)
Settings.py
version.txt

Das ist die Setup.py die ich mit py2app ausprobiert habe:

Code: Alles auswählen

# -*- coding: utf-8 -*-
from setuptools import setup

APP = ['Start.py']
APP_NAME = "App"
DATA_FILES = ['version.txt']

OPTIONS = {
    'argv_emulation': True,
    'plist': {
        'CFBundleName': APP_NAME,
        'CFBundleDisplayName': APP_NAME,
        'CFBundleGetInfoString': "Tagesdaten erfassen",
        'CFBundleVersion': "0.0.1",
        'CFBundleShortVersionString': "0.0.1",
        'NSHumanReadableCopyright': u"Copyright © 2020, Mein Name, All Rights Reserved"
    }
}

setup(
    name=APP_NAME,
    app=APP,
    py_modules=['MainWindow', 'Settings'],
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
was mache ich Falsch? Fehlt noch irgendwas?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja, vor allem der Fehler den du bekommst. Und ein Zahn kann ich dir gleich ziehen: du wirst *nicht* auf dem Mac einen Installer fuer Windows bauen koennen. Die Frage kommt hier gelegentlich mal.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

hallo __deets__,
danke erst mal, dass du dich meldest.
Ja, vor allem der Fehler den du bekommst.
Bild
Im Terminal bekomme ich eigntl. keine Fehler soweit ich mich nich tausche.
du wirst *nicht* auf dem Mac einen Installer fuer Windows bauen koennen.
Das ist nicht das Problem, wenn ich es erstmal am Mac Geschäft habe, kann ich auch auf meinem Windows Laptop das gleiche machen oder?
Und was ist eigentlich mit py2exe?? läuft das nicht auf dem Mac?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na der Fehler hilft nicht wirklich. Du kannst die App direkt im Terminal starten, Meine.app/Contents/MacOS/Meine oder so. Und dann bekommst du auch eine aussagekraeftige Fehlermeldung.

Und nein, py2exe laeuft nicht auf dem mac. Das ist fuer Exes. Also Windows-Anwendungen. Prinzipiell aber kann man den gleichen Code natuerlich auf beiden Plattformen buendeln.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

Danke für den Tip, hier die Meldung aus Terminal:

Code: Alles auswählen

Last login: Wed Mar 18 19:28:05 on ttys000
XXXXXXX-MBP:~ XXXXXXX $ /Users/XXXXXXX/Documents/\=PYTHON\=/\=SPIE\ APP\=\ Kopie/dist/SPIE\ SAG\ App.app/Contents/MacOS/SPIE\ SAG\ App 
Traceback (most recent call last):
  File "/Users/XXXXXXX/Documents/=PYTHON=/=SPIE APP= Kopie/dist/SPIE SAG App.app/Contents/Resources/__boot__.py", line 420, in <module>
    _run()
  File "/Users/XXXXXXX/Documents/=PYTHON=/=SPIE APP= Kopie/dist/SPIE SAG App.app/Contents/Resources/__boot__.py", line 394, in _run
    exec(compile(source, path, "exec"), globals(), globals())
  File "/Users/XXXXXXX/Documents/=PYTHON=/=SPIE APP= Kopie/dist/SPIE SAG App.app/Contents/Resources/Start.py", line 2, in <module>
    import dropbox
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 618, in _load_backward_compatible
  File "<frozen zipimport>", line 259, in load_module
  File "dropbox/__init__.pyc", line 3, in <module>
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 618, in _load_backward_compatible
  File "<frozen zipimport>", line 259, in load_module
  File "dropbox/dropbox.pyc", line 41, in <module>
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 618, in _load_backward_compatible
  File "<frozen zipimport>", line 259, in load_module
  File "dropbox/session.pyc", line 32, in <module>
  File "pkg_resources/__init__.pyc", line 1144, in resource_filename
  File "pkg_resources/__init__.pyc", line 1735, in get_resource_filename
NotImplementedError: resource_filename() only supported for .egg, not .zip
2020-03-18 19:30:12.242 SPIE SAG App[12589:1290537] SPIE SAG App Error
XXXXXXX-MBP:~ XXXXXXX $ 
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Joa. Dis klingt nach einem Problem mit einer Bibliothek die du benutzt, namentlich dropbox. Die laed wahrscheinlich eine DLL nach, und will dazu einen Resource-Namen aufloesen. Und da knallts. Ich wuerde mal versuchen ein minimales Beispiel zu bauen (also etwas, das das gleiche Problem zeigt, aber ohne Code den du nicht teilen willst), und dich an Roland Oussoren auf der pyobjc-Mailingliste wenden. Der ist der Autor von py2app, und ich finde der reagiert recht flott.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

Ok, vielen Dank, werde es heute Abend testen.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

Hallo nochmal, habe jetzt eine andere Frage bezüglich meines Problems:
Dropbox Import nutze ich um eventuell Das Programm upzudaten. Habe selber keinen Server oder Ähnliches. Und wie oben geschrieben möchte ich das Programm mit meinen Kollegen (10 bis 20 Mann) teilen. Die Update Funktion währe ideal dafür, nur fehlen mir natürlich die Kenntnisse.
Gibt es eventuell eine andere Möglichkeit sowas zu realisieren? Vielleicht iCload oder Google Drive?
Und kann man später, wenn dass Programm als .App bzw. .exe existiert, einfach die Module updaten/austauschen?
Bitte steinigt mich nicht direkt, Google habe ich schon gefragt :) . Kann leider auch kein English, was die Sache noch schwieriger macht.

Heute Abend mache den minimal Beispiel des Apps und poste es hier.

Danke im Voraus
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn das dein Ziel ist, dann wird das so ohne weiteres eh nicht gehen. Du kannst Dropbox benutzen, um neue Versionen zu verteilen. Aber gerade mit neueren OSX-Versionen (Catalina) wirst du in riesen Probleme laufen, wenn du da an der App rumfummelst. Die muss signiert sein, und ein Update muss das erhalten. Da wuerde ich mich eher auf die Suche nach dedzidierten Update-Loesungen machen, die gibt es ja. Auch damit wird das ein ganz schoener Brocken, und den wuerde ich erst angehen, wenn du etwas hast, das es wert ist geupdatet zu werden.

Hier ein Beispiel zu posten bringt nur begrenzt viel. Ich kann mich nicht garantiert darum kuemmern. Darum der Hinweis auf den offiziellen Maintainer. Der spricht allerdings kein Deutsch, sondern Englisch und Niederlaendisch.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

ok,
Vielen Dank für den Hinweis. Dann werde ich noch ein bißchen recherchieren, wie ich das mache.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

Hallo nochmals,

stehe wieder auf dem Schlauch. und zwar habe ich jetzt testweise eine kleine App erstellt ( mit Fenster, paar Labels und zwei Buttons)
wollte py2app und PyInstaller testen. Mit py2app funktioniert alles soweit, aber mit PyInstaller funktioniert es gar nicht.
Habe mit --windowed, --onefile, und jeweils mit --noconsole versucht, aber Leider ohne Erfolg. App startet nicht. Was mache ich Falsch?
Wenn ich die app im Terminal starte, kommt folgendes:

Code: Alles auswählen

XXX-MBP:~ XXX$ /Users/XXX/Documents/\=PYTHON\=/\=SPIE\ APP\=\ Kopie\ 2/dist/smallApp.app/Contents/MacOS/smallApp ; exit;
[15631] Error loading Python lib '/Users/XXX/Documents/=PYTHON=/=SPIE APP= Kopie 2/dist/smallApp.app/Contents/MacOS/Python': dlopen: dlopen(/Users/XXX/Documents/=PYTHON=/=SPIE APP= Kopie 2/dist/smallApp.app/Contents/MacOS/Python, 10): no suitable image found.  Did find:
	/Users/XXX/Documents/=PYTHON=/=SPIE APP= Kopie 2/dist/smallApp.app/Contents/MacOS/Python: code signature invalid for '/Users/XXX/Documents/=PYTHON=/=SPIE APP= Kopie 2/dist/smallApp.app/Contents/MacOS/Python'

logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Prozess beendet]

und hier der Python Code:

Code: Alles auswählen

#!/usr/bin/python3

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys



class START(QMainWindow):
    # Initialisierung
    def __init__(self, parent=None):
        super(START, self).__init__(parent)
        self.title = 'START der App'

        self.initMe()

    # Initialisierung
    def initMe(self):
        # App-Fenster
        self.setWindowTitle(self.title)
        self.setGeometry(100, 100, 800, 600)

        # StatusBar
        self.statusbar = self.statusBar()
        self.statusbar.setFont(smallFont)
        self.statusbar.showMessage('Erstellt von XXXX')

        # QWidget
        mainWidget = QWidget()
        mainWidget.setLayout(self.VBox_Final())
        self.setCentralWidget(mainWidget)

        self.show()

    def Labels(self):
        self.titleLbl = QLabel()
        self.titleLbl.setText('Small App')
        self.titleLbl.setFont(titleFont)

        self.infoLbl = QLabel()
        self.infoLbl.setText('Bitte Warten...')
        self.infoLbl.setFont(normFont)

        self.info2Lbl = QLabel()
        self.info2Lbl.setText('')
        self.info2Lbl.setFont(normFettFont)

        hbox_title = QHBoxLayout()
        hbox_title.setAlignment(Qt.AlignCenter)
        hbox_title.addWidget(self.titleLbl)

        hbox_info1 = QHBoxLayout()
        hbox_info1.setAlignment(Qt.AlignCenter)
        hbox_info1.addWidget(self.infoLbl)
        hbox_info1.addWidget(self.info2Lbl)

        vbox_info = QVBoxLayout()
        vbox_info.setAlignment(Qt.AlignCenter)
        vbox_info.addLayout(hbox_title)
        vbox_info.addStretch(1)
        vbox_info.addLayout(hbox_info1)
        vbox_info.addStretch(1)

        return vbox_info

    def Buttons(self):
        self.quitBtn = QPushButton('Beenden')
        self.quitBtn.setFont(normFont)
        self.quitBtn.setStatusTip('Das Programm beenden')
        self.quitBtn.setEnabled(True)
        self.quitBtn.clicked.connect(self.quitBtnClicked)

        self.aktuellVersionBtn = QPushButton('Starten')
        self.aktuellVersionBtn.setFont(normFont)
        self.aktuellVersionBtn.setStatusTip('Die vorhanden Version des Programms starten')
        self.aktuellVersionBtn.setEnabled(True)
        self.aktuellVersionBtn.clicked.connect(self.App_Starten)

        hboxButtons = QHBoxLayout()
        hboxButtons.addWidget(self.quitBtn)
        hboxButtons.addWidget(self.aktuellVersionBtn)

        return hboxButtons

    def VBox_Final(self):
        vboxFinal = QVBoxLayout()
        vboxFinal.addLayout(self.Labels())
        vboxFinal.addLayout(self.Buttons())

        return vboxFinal

    def App_Starten(self):
        #from MainWindow import MainWindow
        self.infoLbl.setText('App Starten...')

    def quitBtnClicked(self):
        choice = QMessageBox.question(self, 'Beenden!',
                                            "Sind Sie sicher das Sie das Programm beenden möchten?",
                                            QMessageBox.Yes | QMessageBox.No)
        if choice == QMessageBox.Yes:
            print("Das Programm wurde beendet!!!!")
            sys.exit()
        else:
            print("Das Beenden wurde abgebrochen!!!!")

if __name__ == '__main__':
        app = QApplication(sys.argv)
        # Font
        titleFont = QFont('Helvetica', 20, QFont.ExtraBold, italic=True)
        normFont = QFont('.SF NS Text', 13)
        normFettFont = QFont('.SF NS Text', 13, QFont.ExtraBold)
        smallFont = QFont('.SF NS Text', 10)

        main = START()
        sys.exit(app.exec_())
Die Frage ist warum es mit py2app geht und mit pyinstaller nicht?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Weiss ich nicht. Warum kuemmert es dich, wenn es mit py2app geht?
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

weil ich später die App nicht als einzelne .app Datei haben will, sondern mit Ordnern wo verschiedene Dateien, die dazu gehören extra haben will, oder geht es auch mit py2app?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

So macht man das nicht auf dem mac, das ist alles in dem app-Bundle. Und das ist doch keine Datei, sondern ein Ordner. Und da drin kannst du prinzipiell beliebig viele andere Ordner haben.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

Ja, eigentlich geht es mir hauptsächlich um Windows. Wenn ich später das Programm mit py2exe erstelle(Natürlich vom Windows aus) möchte ich dass man eventuell einzelne Dateien austauschen bzw. bearbeiten kann, ohne Direkt ein neues .exe erstellen zu müssen.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja wenn's dir um Windows geht, warum reden wir dann ueber macOS? Und was fuer Dateien sollen da ausgetauscht und bearbeitet werden?
Antworten