File: pymailgui-products/unzipped/docetc/obsolete/obsolete--mailconfig-gui1.py
""" ================================================================================ NOT USED -- a first attempt at a GUI launcher, but the window could not be erased on Mac OS X for reasons unknown. Replaced with GUI launcher that stays up and spawns PyMailGUI as a process, and PyMailGUI changes to add a command-line arg and a mailconfig.py hook to exec account files. -------------------------------------------------------------------------------- Get default or account-specific mailconfig settings from this directory. [Sep-2016]: GUI launcher - now uses a radio-button GUI to select an account, instead of console input. With this version you can run without a console altogether, though one is still recommended for viewing error messages. See mailconfig_console.py for the original console-based version of this launcher. Example account names in Mailconfigs were also expanded, as they no longer need to be typed on startup; your account names will vary. *Caveat*: this is an arguably-monstrous hack, motivated by the goal of keeping the main PyMailGUI code as close as possible to its original version in the book PP4E. That requires coding extensions outside the original code base, and hooking into the original's imports to augment its startup. OTOH, it works. In short: This module is imported by PyMailGui-PP4E/SharedNames.py when file PyMailGui-PP4E/PyMailGui.py's code is exec'd in-process by the launcher script, ./Launch_PyMailGUI.py. Other mailconfigs in the MailConfigs folder here import and override defaults from MailConfigs/_mailconfig.py, which is a copy of PyMailGui-PP4E/mailconfig.py. This avoids in-place PymailGui changes. When the launcher runs PyMailGUI: -The CWD is set to PyMailGui's (for file opens with relative pathnames). -The launcher's dir is 1st on sys.path (for mailconfig and MailConfigs imports). -PyMailGui's dir is 2nd on sys.path (for all other imports). -In the standalone package, other PP4E imports are nested in PyMailGui's dir. How the launch process works: 1) Launch_PyMailGUI runs PyMailGui-PP4E/PyMailGui.py as inline code, after configuring sys.path to look here first, and setting CWD to PyMailGui's dir. 2) PyMailGui-PP4E code imports the mailconfig.py here (this file, in this dir), instead of the module of the same name in its own dir. 3) mailconfig.py (this) imports * from an account-specific mailconfig_XXX.py in MailConfigs, using a name XXX selected by a user in the GUI (or a default). 4) Account-specific mailconfigs in MailConfigs import and customize settings in MailConfigs/_mailconfig.py - a copy of the PyMailGui-PP4E/mailconfig.py base. The net effect is to replace PyMailGui-PP4E/mailconfig.py with names imported by this file from account-specific modules in this folder's MailConfigs package. This may seem a bit of a hack, and the new GUI version of this script relies on some unusual tkinter call patterns, but it allows PyMailGUI to be run to select from 1 of N accounts unchanged; it was not originally coded for this use case. ================================================================================ """ #------------------------------------------------------------------------------- # Low-level implementation notes: # When this code runs on import, its folder is first on sys.path (for imports), # but CWD is PyMailGUI-PP4E (for relative file names); this doesn't open itself! # # This also uses binary-mode files to ignore the Unicode encoding of base file, # exec() to run an import with a computed module name in this module's scope, # copystat() to copy base's modtime to avoid a .pyc recompile if hasn't changed. # # [Sept-2016]: instead of using all "_X" variable names to avoid clashing with # settings in mailconfig files, now manually deletes own names before importing. # # An os.path.exists(up + 'mailconfig_%s.py' % acct) can't be used to detect # valid inputs: it's case-insensitive on Windows, but Python imports are not! #------------------------------------------------------------------------------- import os, glob, sys, shutil _log = (lambda *args: None) # set to print to display module namespace # # copy base file up to others to be imported and extended # up = '..' + os.sep + 'MailConfigs' + os.sep # up: relative to CWD base = open('mailconfig.py', 'rb') # base version, below copy = open(up + '_mailconfig.py', 'wb') # for others' defaults copy.write(base.read()) # bytewise file copy copy.close() # close to ensure flush shutil.copystat('mailconfig.py', up + '_mailconfig.py') # modtime for recompile # # show account selector GUI window now (yes, during import!) # from tkinter import * win = Tk() win.title('PyMailGUI Launcher') win.protocol('WM_DELETE_WINDOW', sys.exit) topfrm = Frame(win) topfrm.pack(fill=X) Label(topfrm, text='Welcome to PyMailGUI ', bg='white', font=('Arial', (14 if sys.platform.startswith('darwin') else 11), 'bold italic') ).pack(expand=YES, fill=BOTH, side=RIGHT) iconpath = os.path.join('..', 'docetc', 'ICONS', 'mb_plain.gif') gifimg = PhotoImage(file=iconpath) # gif works on all Pys Label(topfrm, image=gifimg, bg='white').pack(expand=NO, side=LEFT) radiofrm = Frame(win, relief=GROOVE, border=5, width=25) radiofrm.pack(fill=BOTH, expand=YES) Label(radiofrm, text='Select your email account').pack() mods = glob.glob(up + 'mailconfig_*.py') # mailconfig_ACCT.py keys = [mod.split('_', 1)[1][:-3] for mod in mods] # allow >1 '_' in acct name acctvar = StringVar() keys.append('(default: PP4E)') for key in keys: Radiobutton(radiofrm, text=key, variable=acctvar, value=key).pack(anchor=NW) acctvar.set(keys[-1]) b1 = Button(win, text='Open', command=win.destroy) b2 = Button(win, text='Cancel', command=sys.exit) for bx in (b1, b2): bx.pack(side=LEFT) if sys.platform.startswith('darwin'): for bx in (b1, b2): bx.config(font='Arial 14 bold') if sys.platform.startswith('darwin'): #-------------------------------------------------------------------- # [2.5] required on Mac OS X (only), else the checkbuttons in the # main window are not displayed in Aqua (blue) active-window style # until users click another window and click this program's window; # caveat: can still lose active style on iconify and common dialogs; # this is a bug in AS's Mac Tk 8.5 -- it's not present in other Tk # ports, and IDLE search dialogs have the same issue; for reasons # TBD, it's enough to use just the lift() below for pymailgui when # it is run from a command line, but the full bit here is required # when run by mac pylaucher on a click; ditto for pymailgui, but # mergeall requires all 3 steps in both contexts... #-------------------------------------------------------------------- win.withdraw() win.lift() win.after_idle(win.deiconify) win.mainloop() # # after window closed and initial mainloop exits: import acct's configs # _acct = acctvar.get() # still available # clean up most names in this scope for _name in list(sys.modules['mailconfig'].__dict__.keys()): try: if _name[:2] != '__' and _name not in ['_acct', 'sys', '_name', '_log']: del sys.modules['mailconfig'].__dict__[_name] except Exception as Why: print(Why) _log('before:', sorted(sys.modules['mailconfig'].__dict__.keys())) # populate this module's scope: can't be a function try: if _acct == '(default: PP4E)': # copy base's names into this from MailConfigs._mailconfig import * # via ".", sys.path[0] else: # copy acct's names into this exec('from MailConfigs.mailconfig_%s import *' % _acct) _log('after: ', sorted(sys.modules['mailconfig'].__dict__.keys())) except: # any config file exception: display and exit import traceback from tkinter import * from tkinter.messagebox import showerror # bogus root win, but this will be rare win = Tk() Label(win, text='PyMailGUI launcher error', height=5, width=50).pack() # exception text in error dialog from io import StringIO buffer = StringIO() print('Error in config file...\n', file=buffer) # or sys.exc_info()[0/1] traceback.print_exc(file=buffer) # or limit=-1 in 3.5+? showerror('PyMailGUI', buffer.getvalue()) # mainloop() not required here sys.exit(1) else: # configs imported okay: proceed with PyMailGUI's code and window pass # though irrelevant in offline mode (e.g., imapfetch, save files) print('servers: %s, %s' % (popservername, smtpservername)) # user: mailtools