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



[Home page] Books Code Blog Python Author Train Find ©M.Lutz