Pull to refresh

С помощью py2exe запаковал в один файл

Вообщим, все началось с того, что я начал изучать язык Python, понравился он мне моментально (перед этим работал только с С++). Я продолжил потихоньку изучать Python, и тут я решил написать что-то полезное для общества, так сказать. Тут же мой друг/начальник/коллега попросил написать програмку для подсчета стоимости печати на плотере (я подрабатываю в фотостудии/рекламном агенстве), я сразу решил делать это приложение не консольным, а в окне (заодно научился работать с PyQt4). Вообщим сначала я очень уж долго розбирался в PyQt, перелапатил наверное 3/4 всего интернета… Все-таки осилил и получилось вот что — image
, НО тут я понял, что использоваться это будет и на других машинах, кроме моей, а там 99% вероятности что нету интерпритатора Python'a…
Что делать? Конечто же загнать это все дело в EXEшник и дело с концами! Сразу обратился к Хабру, вычитал про py2exe, решил и использовать эту утилиту.

Все сначала как обычно — устанавливаем py2exe, создаем setup.py в директории с нашей програмкой в .py, потом cmd($ setup.py py2exe) и получаем две папки, одна из них не нужна для роботы программы, во второй же и лежит сам EXEшник с кучей иных файлов
image
, взял всю эту папку (она по умолчанию называется dist) и скинул на ноут с Windows XP (сам то я пользую 7 Professional N), запускаю мой EXEшник, и ура, заработало!!!

Но я решил на этом не останавливаться — меня не радовала маленькая програмка в виде папки с кучей файлов. И тут понеслась — я перечитал все статьи на Хабре, много пробовал, не плучалось, потом нашел еще один САЙТ, на нем уж я «погулял» очень даже не мало… Вообщим, этими усилиями я добился того что мне py2exe выдавал три файла в сmd ($ setup.py py2exe -b 2, но при этом в setup.py в модуль «includes» нужно добавить импортируемые програмой файлы/библиотеки и еще после опций «zipfile=None») — сам EXEшник, EXEшник для Windows 98 и старше и одну DLLку а именно python27.dll
image
, как я в в самом файле setup.py не извращался, но не смог добиться того чтобы py2exe впихивал и эту DLLку в EXEшник… И тут я решил сделать «шаг конем» — поскольку я в setup.py и так подгружаю PyQt4 библиотеки, почему бы не сделать этот самый python27.dll библиотекой PyQt4? Я взял эту python27.dll и скопировал в ..\Python27\Lib\site-packages\PyQt4 потом запускаем $ setup.py py2exe -b 1 и получаем готовый EXEшник
image
, работающий на других машинах, без установки чего-либо!

Готовый EXEшник скачать можно здесь

Вот код setup.py:
from distutils.core import setup
import py2exe
 
setup(
    windows=[{"script":"Sindaria_Ploter_print.py"}],
    options={"py2exe": {"includes":["sip","qad","dialog","sys","PyQt4"]}},
    zipfile=None

)

Где «Sindaria_Ploter_print.py» это вот:
import sys
import dialog
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtCore, QtGui
import qad
class MyClass(QDialog, dialog.Ui_Dialog):
    def __init__(self, parent=None):
        QDialog.__init__(self,parent)
        self.setupUi(self)
        self.connect(self.pushButton, SIGNAL("clicked()"), self.actionOnButton)
        self.connect(self.pushButton_2,QtCore.SIGNAL("clicked()"),QtCore.SLOT('close()'))
        self.checkBox_2.setEnabled(False)
        self.checkBox.setEnabled(False)
        self.connect(self.radioButton,QtCore.SIGNAL("toggled(bool)"),self.onbtn)
        self.connect(self.radioButton_2,QtCore.SIGNAL("toggled(bool)"),self.ofbtn)
        self.connect(self.radioButton_3,QtCore.SIGNAL("toggled(bool)"),self.ofbtn)
    def onbtn(self):
        self.checkBox_2.setEnabled(True)
        self.checkBox.setEnabled(True)
    def ofbtn(self):
        self.checkBox_2.setChecked(False)
        self.checkBox_2.setEnabled(False)
        self.checkBox.setChecked(False)
        self.checkBox.setEnabled(False)
    def actionOnButton(self):
        p=0   
        k=0
        if self.checkBox_2.isChecked():
            p=1
        if self.checkBox.isChecked():
            k=1
        if self.radioButton.isChecked():
            l=1
        if self.radioButton_2.isChecked():
            l=2
        if self.radioButton_3.isChecked():
            l=3
    	x=int(self.lineEdit.text())
        y=int(self.lineEdit_2.text())
        v = qad._set(x,y,int(self.spinBox.value()),l)
        if l==1:
            r=v*2.4
        else:
            r=v*2
        v=str(v)
        r=r-(r*(int(self.spinBox_2.value()))*0.01)
        if p==1:
            if k==1:
                r=r+((x+y)*0.05)+((x*y*0.045)/1000)
            else:
                r=r+((x+y)*0.05)
        r=str(r)
        self.label_5.setText(v)
        self.label_8.setText(r)
if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyClass()
    w.show()
    app.exec_()

Файл qad представляет собой вот это:
def _set(x,y,o,z):
	k=(y*x)*0.02
	k=(k*0.29)+(k*0.7)
	if z==1	:
		l=k+(x*y*(0.0536+0.03))
	if z==2 :
		l=k+(x*y*(0.0099+0.03))
	if z==3 :
		l=k+(x*y*(0.02156+0.03))
	l=l/1000
	l=l*o
	return l

Вот dialog.py:
from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName(_fromUtf8("Dialog"))
        Dialog.resize(417, 176)
        self.lineEdit = QtGui.QLineEdit(Dialog)
        self.lineEdit.setGeometry(QtCore.QRect(10, 20, 113, 20))
        self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
        self.lineEdit_2 = QtGui.QLineEdit(Dialog)
        self.lineEdit_2.setGeometry(QtCore.QRect(10, 50, 113, 20))
        self.lineEdit_2.setObjectName(_fromUtf8("lineEdit_2"))
        self.groupBox = QtGui.QGroupBox(Dialog)
        self.groupBox.setGeometry(QtCore.QRect(200, 20, 120, 111))
        self.groupBox.setObjectName(_fromUtf8("groupBox"))
        self.radioButton = QtGui.QRadioButton(self.groupBox)
        self.radioButton.setGeometry(QtCore.QRect(20, 20, 82, 17))
        self.radioButton.setObjectName(_fromUtf8("radioButton"))
        self.radioButton_2 = QtGui.QRadioButton(self.groupBox)
        self.radioButton_2.setGeometry(QtCore.QRect(20, 50, 82, 17))
        self.radioButton_2.setObjectName(_fromUtf8("radioButton_2"))
        self.radioButton_3 = QtGui.QRadioButton(self.groupBox)
        self.radioButton_3.setGeometry(QtCore.QRect(20, 80, 82, 17))
        self.radioButton_3.setObjectName(_fromUtf8("radioButton_3"))
        self.label = QtGui.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(140, 20, 46, 13))
        self.label.setObjectName(_fromUtf8("label"))
        self.label_2 = QtGui.QLabel(Dialog)
        self.label_2.setGeometry(QtCore.QRect(140, 50, 46, 13))
        self.label_2.setObjectName(_fromUtf8("label_2"))
        self.label_3 = QtGui.QLabel(Dialog)
        self.label_3.setGeometry(QtCore.QRect(60, 80, 46, 13))
        self.label_3.setObjectName(_fromUtf8("label_3"))
        self.spinBox = QtGui.QSpinBox(Dialog)
        self.spinBox.setGeometry(QtCore.QRect(10, 80, 42, 22))
        self.spinBox.setMinimum(1)
        self.spinBox.setObjectName(_fromUtf8("spinBox"))
        self.pushButton = QtGui.QPushButton(Dialog)
        self.pushButton.setGeometry(QtCore.QRect(230, 140, 75, 23))
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
        self.pushButton_2 = QtGui.QPushButton(Dialog)
        self.pushButton_2.setGeometry(QtCore.QRect(330, 140, 75, 23))
        self.pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
        self.label_4 = QtGui.QLabel(Dialog)
        self.label_4.setGeometry(QtCore.QRect(10, 120, 71, 16))
        self.label_4.setObjectName(_fromUtf8("label_4"))
        self.label_5 = QtGui.QLabel(Dialog)
        self.label_5.setGeometry(QtCore.QRect(110, 140, 46, 13))
        self.label_5.setText(_fromUtf8(""))
        self.label_5.setObjectName(_fromUtf8("label_5"))
        self.checkBox_2 = QtGui.QCheckBox(Dialog)
        self.checkBox_2.setGeometry(QtCore.QRect(330, 50, 70, 17))
        self.checkBox_2.setObjectName(_fromUtf8("checkBox_2"))
        self.label_6 = QtGui.QLabel(Dialog)
        self.label_6.setGeometry(QtCore.QRect(340, 30, 71, 16))
        self.label_6.setObjectName(_fromUtf8("label_6"))
        self.label_7 = QtGui.QLabel(Dialog)
        self.label_7.setGeometry(QtCore.QRect(10, 140, 91, 16))
        self.label_7.setObjectName(_fromUtf8("label_7"))
        self.label_8 = QtGui.QLabel(Dialog)
        self.label_8.setGeometry(QtCore.QRect(110, 120, 46, 13))
        self.label_8.setText(_fromUtf8(""))
        self.label_8.setObjectName(_fromUtf8("label_8"))
        self.label_9 = QtGui.QLabel(Dialog)
        self.label_9.setGeometry(QtCore.QRect(140, 80, 51, 16))
        self.label_9.setObjectName(_fromUtf8("label_9"))
        self.spinBox_2 = QtGui.QSpinBox(Dialog)
        self.spinBox_2.setGeometry(QtCore.QRect(100, 80, 42, 22))
        self.spinBox_2.setMinimum(0)
        self.spinBox_2.setProperty("value", 0)
        self.spinBox_2.setObjectName(_fromUtf8("spinBox_2"))
        self.checkBox = QtGui.QCheckBox(Dialog)
        self.checkBox.setGeometry(QtCore.QRect(330, 70, 70, 17))
        self.checkBox.setObjectName(_fromUtf8("checkBox"))

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Cost calc", None, QtGui.QApplication.UnicodeUTF8))
        self.groupBox.setTitle(QtGui.QApplication.translate("Dialog", "Материал", None, QtGui.QApplication.UnicodeUTF8))
        self.radioButton.setText(QtGui.QApplication.translate("Dialog", "Холст", None, QtGui.QApplication.UnicodeUTF8))
        self.radioButton_2.setText(QtGui.QApplication.translate("Dialog", "Бумага", None, QtGui.QApplication.UnicodeUTF8))
        self.radioButton_3.setText(QtGui.QApplication.translate("Dialog", "Ткань", None, QtGui.QApplication.UnicodeUTF8))
        self.label.setText(QtGui.QApplication.translate("Dialog", "Высота", None, QtGui.QApplication.UnicodeUTF8))
        self.label_2.setText(QtGui.QApplication.translate("Dialog", "Ширина", None, QtGui.QApplication.UnicodeUTF8))
        self.label_3.setText(QtGui.QApplication.translate("Dialog", "Копий", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton.setText(QtGui.QApplication.translate("Dialog", "Просчитать", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton_2.setText(QtGui.QApplication.translate("Dialog", "Выход", None, QtGui.QApplication.UnicodeUTF8))
        self.label_4.setText(QtGui.QApplication.translate("Dialog", "Стоимость :", None, QtGui.QApplication.UnicodeUTF8))
        self.checkBox_2.setText(QtGui.QApplication.translate("Dialog", "Натяжка", None, QtGui.QApplication.UnicodeUTF8))
        self.label_6.setText(QtGui.QApplication.translate("Dialog", "Для холста :", None, QtGui.QApplication.UnicodeUTF8))
        self.label_7.setText(QtGui.QApplication.translate("Dialog", "Себестоимость :", None, QtGui.QApplication.UnicodeUTF8))
        self.label_9.setText(QtGui.QApplication.translate("Dialog", "% скидка", None, QtGui.QApplication.UnicodeUTF8))
        self.checkBox.setText(QtGui.QApplication.translate("Dialog", "Лак", None, QtGui.QApplication.UnicodeUTF8))



Все эти 4 скрипта (Sindaria_Ploter_print.py, setup.py,

Конечно код пугает меня самого, но я здесь не о коде пишу, а каким образом смог добиться полного «упаковывания» моейго скрипта.py в .EXE

P.S кто решит впервые пробовать py2exe после этой статьи, то команда py2exe в cmd исполняеться находясь в директории с самим setup.py
P.P.S файл «w9xpopen.exe» можете более чем смело удалять, он не влияет на работоспособность основной_програмы.exe
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.