Esse post é o primeiro da série Distribuir Programas em Python para Desktops Windows. Esse é o mais básico de todos, e esse assunto já foi bem discutido em diversos sites, mas a minha ideia aqui é apresentar como criei o programa de exemplo, mostrar como posso gerar um instalador bem simples já com as bibliotecas que o programa precisa pra rodar em outros Windows.
Toda vez que você gera um executável em Python, o windows precisa das DLLs de Runtime do C++, o tal do Microsoft Visual C++ Redistributable, você vai encontrar como MSVCR. A versão que será necessária depende de qual versão do Python você está usando.
- Python 2.4 ou Python 2.5 – Microsoft Visual C++ 2005 Redistributable Package
- Python 2.6, 2.7 ou 3.x – Microsoft Visual C++ 2008 Redistributable Package
Nós temos três coisas a fazer:
- Criar o script do programa
- Criar um arquivo de setup para gerar o executável.
- Gerar o Instalador MSI
Vou criar um script besta em python só pra ilustrar esses posts, isso é de uma brincadeira idiota que fiz com um amigo meu. Toda vez que o usuário apertar Print Screen o aplicativo vai abrir uma foto de uma boneca, como da foto abaixo:
#boneca.py
import os
import sys
import ctypes
from ctypes import wintypes
import win32con
byref = ctypes.byref
user32 = ctypes.windll.user32
HOTKEYS = {
1 : (win32con.VK_SNAPSHOT, 0), ####Essa Linha Pega a tecla "PRINT SCREEN"
2 : (win32con.VK_F4, win32con.MOD_WIN)
}
def handle_win_f3 ():
os.startfile(os.path.join(os.path.realpath(os.path.dirname(sys.argv[0])),"boneca.jpg"))
def handle_win_f4 ():
user32.PostQuitMessage (0)
HOTKEY_ACTIONS = {
1 : handle_win_f3,
2 : handle_win_f4
}
# Registrando as chaves sem dar o print pra ficar escondido na tela.
for id, (vk, modifiers) in HOTKEYS.items ():
#print "Registering id", id, "for key", vk
pass
if not user32.RegisterHotKey (None, id, modifiers, vk):
#print "Unable to register id", id
pass
# Executando as funções e tirando o registro das chaves depois do encerramento do programa.
try:
msg = wintypes.MSG ()
while user32.GetMessageA (byref (msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
action_to_take = HOTKEY_ACTIONS.get (msg.wParam)
if action_to_take:
action_to_take ()
user32.TranslateMessage (byref (msg))
user32.DispatchMessageA (byref (msg))
finally:
for id in HOTKEYS.keys ():
user32.UnregisterHotKey (None, id)
Como referência pra esse código eu usei o post do Tim Golden[1].
O código é simples, ele cria dois atalhos no windows, um é o Print Screen que quando pressionado roda a função handle_win_f3 que faz a chamada da foto da boneca.jpg
Já quando ele pressionar o atalho Win + F4 será executada a função handle_win_f4 que apenas encerra o programa. Ele não tem interface gráfica, o que faz sentido pra essa brincadeira.
Beleza, até aí só um script python fácil, agora nós precisamos fazer o Frozen dessa aplicação. Gerar um Frozen (um módulo congelado) é compilar o script e gerar um executável que contenha o interpretador python, suas bibliotecas, seu script e seus arquivos tudo em um lugar só e com um executável (ou mais executáveis). Para isso você precisa criar um arquivo de setup e escolher uma ferramenta para fazer o frozen, os mais usados são py2exe, py2app, cx_freeze, e o pyinstaller. Nesse caso eu vou usar o cx_freeze. Esse arquivo por convenção é chamado de setup.py e
#setup.py
from cx_Freeze import setup, Executable
setup(
name = "boneca",
version = "1.0.0",
options = {"build_exe": {
'packages': ["os","sys","ctypes","win32con"],
'include_files': ['boneca.jpg'],
'include_msvcr': True,
}},
executables = [Executable("boneca.py",base="Win32GUI")]
)
O script também é simples, ele segue a mesma lógica do disutils , só quero chamar atenção para o include_msvcr que vai colocar as DLLs do Microsoft Visual C++ Redistributable no seu executável, dessa forma ele vai copiar as DLLs que já existem no seu sistema operacional. Esse é o único jeito do seu programa funcionar em outros windows, pois o Python precisa dessas dlls para ser executado. Você também pode baixar o próprio instalador do MSVCR da Microsoft e incorporar no seu instalador usando o Inno Setup, por exemplo, vou mostrar isso em um dos próximos posts da série.
Agora vamos gerar um MSI, ou seja, um instalador para windows. Só rodar na linha de comando:
python setup.py bdist_msi
Beleza, agora ele criou uma pasta chamada dist com um arquivo boneca-1.0.0-win32.msi (ou boneca-1.0.0-amd64.msi se seu sistema for 64) agora já dá pra instalar e usar. Então aqui mostrei Como criar um executável com Instalador MSI em Python e com Cx_freeze.
Os scripts estão no meu Github: https://github.com/ffreitasalves/boneca
[1]: http://timgolden.me.uk/python/win32_how_do_i/catch_system_wide_hotkeys.html
Excelente tutorial
Muito obrigado me ajudou bastante
Fico feliz que tenha ajudado. Foi osso quando comecei a mexer com isso, por isso resolvi anotar
Obrigado pelo tutorial, muito bom.
Eu estou com um problema, o cx_Freeze não está importando as bibliotecas do PyQt5, eu as incluo no script do setup mas não adianta.
Isso já aconteceu com vc ?
Cara, não usei com o PyQt5, usei com o PySide (equivalente ao PyQT4) e coloquei no includes = [‘PySide’,], no setup.py e no options do setup eu colocava desse jeito aqui:
from cx_Freeze import setup
includes = [‘PySide’,]
setup(
…
options={“build_exe”:
{“packages”:packages,
“includes”: includes,
“include_files”: include_files,
“excludes”: excludes,
“optimize”: 2,
“icon”:”icon-16px.ico”,
},
“bdist_esky”:{
‘freezer_module’:”cxfreeze”,
‘includes’: includes,
‘excludes’: excludes,
},
…
)
E valeu por ter gostado
Muito bom o post, parabéns.
Muito obrigado!
Caro Fernando,
Você saberia me dizer se há algo que precisaria ser modificado no setup.py caso o programa desenvolvido em Python não tenha interface GUI, sendo somente console?
É que usei o seu tutorial pra empacotar uma aplicação que estou desenvolvendo aqui, mas ao tentar executar o arquivo .exe gerado, tenho este erro retornado.
Saberia, só com base nisso, me dizer se fiz algo errado?
Grato!
Fala ae Fabrício. Primeiro, no setup.py vc tá usando o quê? py2exe ou cx_freeze? Se for o py2exe fica super fácil é só criar um arquivo mais ou menos assim:
Se estiver usando o esky como eu mostrei é só trocar o gui_only pra False
Se for com o cx_freeze é só tirar o argumento base=base, (pq to usando um base=Win32Gui mas o default é um que usa o console)
E o erro é de importação, você precisa colocar as dependências na lista de packages (no caso o configparser).
[]’s
Olá, eu tenho um executável de um código que um colega me passou, porem em minha pesquisa tenho que realizar algumas modificações no código, existe alguma maneira de realizar essas modificações sem o código fonte?
Cara, não tem como. :/
Muito obrigado pelo tutorial, bem simples e eficaz. Entretanto, eu to tendo um erro aqui, e queria pedir sua ajuda, o erro é o seguinte:
Traceback (most recent call last):
File “setup.py”, line 2, in
from cx_Freeze import setup, Executable
File “C:\Python27\lib\site-packages\cx_Freeze\__init__.py”, line 10, in
from cx_Freeze.freezer import *
File “C:\Python27\lib\site-packages\cx_Freeze\freezer.py”, line 11, in
import socket
File “C:\Python27\lib\socket.py”, line 47, in
import _socket
ImportError: DLL load failed: Não foi possível encontrar o procedimento especificado.
Pedro, tenta instalar os pacotes com esses binarios aqui: http://www.lfd.uci.edu/~gohlke/pythonlibs/
tem o cx_freeze pra instalar.
Boa tarde Fernando. Que grande post esse seu sobre executáveis Python.
Gostaria de tirar uma dúvida se possível.
com relação as dll MSVCR. A versão a utilizar vai de acordo com a versão do python ou com a versão do SO que estará no computador? Pelo que entendi a versão Microsoft Visual C++ 2008 Redistributable Package irá funcionar em qualquer computador desde que eu esteja utilizando python 2.6++. Entendi corretamente?
fernando, boa tarde
estou desenvolvendo um app que utliza wxpython e outros modulos e a tentativa de distribuir aqui na firma tem sido frustrante pois é para windows (msm se fosse linux muitas vezes não tem a versão correta)
eu consigo fazer o executável seja utilizando o cxfreeze ou pyinstaller mas eles ativam o antivírus e não consigo. Será que criando o msi para instalar efetivamente faz com que o antivírus pare de encher o saco?
Vlw
Fala Maurício, tudo bem?
Cara, eu também já tive esse problema com o antivírus, principalmente nos Windows 8 e 10.
Usando o Inno Setup pra criar o instalador diminuiu um pouco o problema, mas o que pode deixar o seu programa mais confiável pro windows, sem que o cara tenha que ficar adicionando seu programa no antivírus é usar algum code signing.
Dá uma olhada nesses preços que eu pesquisei…já faz tempo, mas era mais ou menos assim.
http://3.230.47.72/como-criar-um-instalador-msi-utilizando-o-inno-setup/#observacoes_codesigning
Acho que é o melhor jeito.
[]’s
Vlw!
Boa noite ffreitasalves:
escrevo para vc porque rodei o seu script e deu todo bem mas rodei o meu que tem o PyQt4 no meio e deu erro num modulo de PyQt4 chamado ‘PyQt4.uic.port_v3.proxy_base’, o que vc aconselha nesse caso ?
Estou com o mesmo problema! :/
Boa tarde Fernando,
antes de mais nada, parabéns!! A forma como você explica as coisas é ímpar e muito tem me ajudado.
Estou tendo um problema quando uso o matplotlib, se faço somente para gerar um executável consigo gerar os gráficos normalmente. No entanto quando uso o instalador, não aparece mensagem de erro e nem os gráficos. Você saberia o que pode causar isso?
Desde já agradeço, e muito sucesso!!
Fala Ricardo, obrigado pelo elogio!
Sinceramente não conheço as particularidades do matplotlib pra rodar no executável, mas acredito que pode ser alguma coisa faltando nos includes no setup.py.
Dá uma olhada nesse link aqui:
https://gist.github.com/joferkington/9214844
Nos includes e nos includes_files dele tem alguma coisa um pouco tricky!
Olá Fernando, meus parabéns pelo excelente blog e muito obrigado por essa dica valiosa em Python.
Eu fiz uma aplicação de terminal e utilizei esse método para empacotar tudo e executar em computadores sem Python instalado. Até aí tudo bem.
Quando tento executar a aplicação nos computadores Clientes eles me retornam erro de DLL, com um pouco de pesquisa pude identificar que exigiam baixar as DLLs Runtime, mesmo usando a opção no setup.py que já inclui as mesmas.
No caso, o programa só foi executado após instalar manualmente a DLL Visual C++ Redistributable for Visual Studio 2015.
Minha pergunta é: Consigo incluir manualmente essa DLL no meu executável? Através das opções do Setup.py, em vez de instalar manualmente em cada computador que a aplicação for executada.
O estranho é que a DLL que ele reclama que não tem, está dentro da pasta “lib” no diretório de instalação do programa.
VCRUNTIME140.DLL
cara o ideal é criar um instalador mais parrudo, dá uma olhada nessa terceira parte aqui, acho que pode te ajudar:
http://3.230.47.72/como-criar-um-instalador-msi-utilizando-o-inno-setup/
Olá Fernando. Criei um sisteminha com umas 3 telas. Executei todos os passos do tutorial e ele gerou direitinho o instalador. Porém quando executo o programa instalado ele não sai da tela inicial. O que pode ser?
Oi Vinícius, não sei :/
Olá Fernando, Muito bom msm, parabens.
Tenho uma duvida, se puder me responder agradeço.
Preciso gerar uma lista com os programas instalados no windows usando o python.
No python tem algum modulo que posso usar para acessar estas informações do windows?
No cmd eu usar wmic.
abraço e sucesso.
se puder me ajudar agradeço.
Olá Rubens, tudo bem?
Eu já usei o win32com para fazer isso uma vez. Esse link poderá te ajudar: http://timgolden.me.uk/pywin32-docs/html/com/win32com/HTML/QuickStartClientCom.html
Ótimo Artigo, tive algumas dificuldades na instação do Cx_freeze, porém olhando um pouco no Stack Overflow resolveu o meu problema.
Olá Fernando,
Primeiramente seu tutorial é muito bom, está de parabéns pelo trabalho. Sou iniciante com python (na programação em si), e estou trabalhando seguidamente com PyQt5. Provavelmente ainda terei que usar o conhecimento que compartilhou. Então, gostaria de saber com relação a programas que contenham banco de dados..Acredito que ele não será importado e terei que instalar no usuário?..é isso, desculpe minha ignorância, pois pretendo usar o MySQL ou o Postgres…O que vc indica fazer nesse caso?
Muito obrigado Robson.
Robson, eu acho que instalar o postgres ou mysql no computador do usuário é pesado demais, mas depende do tipo de programa que você está desenvolvendo. Se é necessário usar um banco de dados local e por usuário eu pensaria em utilizar o sqlite mesmo.
No caso de ter que usar um outro banco de dados, você poderia configurar seu BD online e o seu programa acessar esse outro host para o banco de dados.
E nos outros casos, como um programa mais técnico que pode ser usado por administradores e gerentes de rede, normalmente esses profissionais estão acostumados com programas nos quais eles são obrigados a instalar um banco de dados para funcionar junto com o programa, então poderia apenas descrever os passos de como instalar o banco e seu programa criaria as tabelas, depois de receber um usuário e senha.
Se você der uma olhada no próximo passo do tutorial você também vai ver como usar o inno setup para distribuir seu programa e eu acredito que você consegue colocar o mysql ou o postgres para instalar juntamente com o programa!
um abraço!