问题
So i'm having issues getting my python 3.5 script to run as an exe. Here is the code I am using:
import base64
import imaplib
import json
import smtplib
import urllib.parse
import urllib.request
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import lxml.html
GOOGLE_ACCOUNTS_BASE_URL = 'https://accounts.google.com'
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
GOOGLE_CLIENT_ID = '<FILL ME IN>'
GOOGLE_CLIENT_SECRET = '<FILL ME IN>'
GOOGLE_REFRESH_TOKEN = None
def command_to_url(command):
return '%s/%s' % (GOOGLE_ACCOUNTS_BASE_URL, command)
def url_escape(text):
return urllib.parse.quote(text, safe='~-._')
def url_unescape(text):
return urllib.parse.unquote(text)
def url_format_params(params):
param_fragments = []
for param in sorted(params.items(), key=lambda x: x[0]):
param_fragments.append('%s=%s' % (param[0], url_escape(param[1])))
return '&'.join(param_fragments)
def generate_permission_url(client_id, scope='https://mail.google.com/'):
params = {}
params['client_id'] = client_id
params['redirect_uri'] = REDIRECT_URI
params['scope'] = scope
params['response_type'] = 'code'
return '%s?%s' % (command_to_url('o/oauth2/auth'), url_format_params(params))
def call_authorize_tokens(client_id, client_secret, authorization_code):
params = {}
params['client_id'] = client_id
params['client_secret'] = client_secret
params['code'] = authorization_code
params['redirect_uri'] = REDIRECT_URI
params['grant_type'] = 'authorization_code'
request_url = command_to_url('o/oauth2/token')
response = urllib.request.urlopen(request_url, urllib.parse.urlencode(params).encode('UTF-8')).read().decode('UTF-8')
return json.loads(response)
def call_refresh_token(client_id, client_secret, refresh_token):
params = {}
params['client_id'] = client_id
params['client_secret'] = client_secret
params['refresh_token'] = refresh_token
params['grant_type'] = 'refresh_token'
request_url = command_to_url('o/oauth2/token')
response = urllib.request.urlopen(request_url, urllib.parse.urlencode(params).encode('UTF-8')).read().decode('UTF-8')
return json.loads(response)
def generate_oauth2_string(username, access_token, as_base64=False):
auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token)
if as_base64:
auth_string = base64.b64encode(auth_string.encode('ascii')).decode('ascii')
return auth_string
def test_imap(user, auth_string):
imap_conn = imaplib.IMAP4_SSL('imap.gmail.com')
imap_conn.debug = 4
imap_conn.authenticate('XOAUTH2', lambda x: auth_string)
imap_conn.select('INBOX')
def test_smpt(user, base64_auth_string):
smtp_conn = smtplib.SMTP('smtp.gmail.com', 587)
smtp_conn.set_debuglevel(True)
smtp_conn.ehlo('test')
smtp_conn.starttls()
smtp_conn.docmd('AUTH', 'XOAUTH2 ' + base64_auth_string)
def get_authorization(google_client_id, google_client_secret):
scope = "https://mail.google.com/"
print('Navigate to the following URL to auth:', generate_permission_url(google_client_id, scope))
authorization_code = input('Enter verification code: ')
response = call_authorize_tokens(google_client_id, google_client_secret, authorization_code)
return response['refresh_token'], response['access_token'], response['expires_in']
def refresh_authorization(google_client_id, google_client_secret, refresh_token):
response = call_refresh_token(google_client_id, google_client_secret, refresh_token)
return response['access_token'], response['expires_in']
def send_mail(fromaddr, toaddr, subject, message):
access_token, expires_in = refresh_authorization(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN)
auth_string = generate_oauth2_string(fromaddr, access_token, as_base64=True)
msg = MIMEMultipart('related')
msg['Subject'] = subject
msg['From'] = fromaddr
msg['To'] = toaddr
msg.preamble = 'This is a multi-part message in MIME format.'
msg_alternative = MIMEMultipart('alternative')
msg.attach(msg_alternative)
part_text = MIMEText(lxml.html.fromstring(message).text_content().encode('utf-8'), 'plain', _charset='utf-8')
part_html = MIMEText(message.encode('utf-8'), 'html', _charset='utf-8')
msg_alternative.attach(part_text)
msg_alternative.attach(part_html)
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo(GOOGLE_CLIENT_ID)
server.starttls()
server.docmd('AUTH', 'XOAUTH2 ' + auth_string)
server.sendmail(fromaddr, toaddr, msg.as_string())
server.quit()
def main():
if GOOGLE_REFRESH_TOKEN is None:
print('No refresh token found, obtaining one')
refresh_token, access_token, expires_in = get_authorization(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
print('Set the following as your GOOGLE_REFRESH_TOKEN:', refresh_token)
exit()
send_mail('--------@gmail.com', '--------@gmail.com',
'A mail from you from Python',
'<b>A mail from you from Python</b><br><br>' +
'So happy to hear from you!')
input("Success!")
print(__name__)
input("Wait!!")
if __name__ == '__main__':
main()
When i run the code in pyCharm is works great, when i use pyinstaller it creates the exe. When i run the EXE it will open a new cmd prmpt with no text in it, then it closes. Any ideas why it doesn't print the name or "Wait!!" on the screen? I named the file main and it works great in PyCharm. I'm not familiar with troubleshooting code that works in an IDE and does nothing as an exe. Is there a basic troubleshooting guide for that?
回答1:
Most of the problems are errors caused by imported modules.
Here are two ways I think of
- Use exception handling and use
traceback.format_exc()
to display the contents when an error occurs. - Errors are usually associated with the
sys.stderr
, so you can redirect stderr output a specified format to a specified file or the like.
Example:
import sys
from pathlib import Path
from os import startfile
import traceback
DEBUG = True
class CaptureStderr:
__slots__ = ('debug_flag',
'original',
'log',)
def __init__(self, debug_flag=False, log=None):
self.debug_flag = debug_flag
self.original = sys.stderr # Keep track of original
self.log = log
def new_log_file(self, log_path: Path = Path('temp.log').resolve()):
self.log = open(str(log_path), 'w')
return self.log
def start(self):
""" Start filtering and redirecting stderr """
sys.stderr = self
def stop(self):
""" Stop filtering and redirecting stderr """
sys.stderr = self.original
def write(self, message: str):
""" When sys.stderr.write is called, it will re directed here"""
if not self.debug_flag:
self.original.write(message)
self.original.flush()
return
if self.log:
self.log.write(message)
def main():
...
if __name__ == '__main__':
try: # method 1
from .notexistmodule import notexistclass
# Put modules that you are not sure whether it is 100% import successful on here.
main()
except:
print(traceback.format_exc())
# method 2: redirect sys.stderr
cs = CaptureStderr(DEBUG)
cs.new_log_file(Path('error.log'))
cs.start()
from .notexistmodule2 import notexistclass2
main()
cs.stop()
startfile(cs.log.name)
回答2:
You probably have an error in the exe, most likely an import error.
Run your exe like this to see the error: Create a .bat file to run the exe with the following commands
start C:\Path\To\.exe
pause
This will stop the command prompt from exiting until you press a key on the keyboard, letting you read the output.
来源:https://stackoverflow.com/questions/60698419/cant-get-python-exe-to-run