In this chapter, we
focused on client-side interfaces to standard protocols that
run over sockets, but as suggested in an earlier footnote, client-side
programming can take other forms, too. We outlined many of these at the
start of
Chapter 12
—web service protocols
(including SOAP and XML-RPC); Rich Internet Application toolkits
(including Flex, Silverlight, and pyjamas); cross-language framework
integration (including Java and .NET); and more.
As mentioned, most of these serve to extend the functionality of web
browsers, and so ultimately run on top of the HTTP protocol we explored in
this chapter. For instance:
The
Jython
system,
a compiler that supports Python-coded Java
applets—general-purpose programs downloaded from a server and run
locally on the client when accessed or referenced by a URL, which
extend the functionality of web browsers and interactions.
Similarly,
RIAs
provide AJAX communication
and widget toolkits that allow JavaScript to implement user
interaction within web browsers, which is more dynamic and rich than
HTML and web browsers otherwise support.
In
Chapter 19
, we’ll also study
Python’s support for XML—structured text that is used as the data
transfer medium of client/server dialogs in
web
service
protocols such as XML-RPC, which transfer
XML-encoded objects over HTTP, and are
supported
by Python’sxmlrpc
standard library package. Such protocols can simplify
the interface to web servers in their clients.
In deference to time and space, though, we won’t go into further
details on these and other client-side tools here. If you are interested
in using Python to script clients, you should take a few minutes to become
familiar with the list of Internet tools documented in the Python library
reference manual. All work on similar principles but have slightly
distinct interfaces.
In
Chapter 15
, we’ll hop the fence to
the other side of the Internet world and explore scripts that run on
server machines. Such programs give rise to the grander notion of
applications that live entirely on the Web and are launched by web
browsers. As we take this leap in structure, keep in mind that the tools
we met in this and the preceding chapter are often sufficient to implement
all the distributed processing that many applications require, and they
can work in harmony with scripts that run on a server. To completely
understand the Web worldview, though, we need to explore the server realm,
too.
Before we get there, though, the next chapter puts concepts we’ve
learned here to work by presenting a complete client-side program—a
full-blown mail client GUI, which ties together many of the tools we’ve
learned and coded. In fact, much of the email work we’ve done in this
chapter was designed to lay the groundwork we’ll need to tackle the
realistically scaled PyMailGUI example of the next chapter. Really, much
of this book so far has served to build up skills required to equip us for
this task: as we’ll see,
PyMailGUI
combines system tools, GUIs, and client-side Internet protocols to produce
a useful system that does real work. As an added bonus, this example will
help us understand the trade-offs between the client solutions we’ve met
here and the server-side solutions we’ll study later in this part of the
book.
The preceding chapter introduced Python’s client-side Internet
protocols tool set—the standard library modules available for email, FTP,
network news, HTTP, and more, from within a Python script. This chapter
picks up where the last one left off and presents a complete client-side
example—PyMailGUI, a Python program that sends, receives, composes, and
parses Internet email messages.
Although the end result is a working program that you can actually
use for your email, this chapter also has a few additional agendas worth
noting before we get started:
PyMailGUI
implements a full-featured desktop GUI that runs on
your machine and communicates with your mail servers when necessary.
As such, it is a network client program that further illustrates
some of the preceding chapter’s topics, and it will help us contrast
server-side solutions introduced in the next chapter.
Additionally, PyMailGUI ties together a number of the utility
modules we’ve been writing in the book so far, and it demonstrates
the power of code reuse in the
process—
it uses a thread module to
allow mail transfers to overlap in time, a set of mail modules to
process message content and route it across networks, a window
protocol module to handle icons, a text editor component, and so on.
Moreover, it inherits the power of tools in the Python standard
library, such as theemail
package; message construction and parsing, for example, is nearly
trivial here.
And finally, this chapter serves to illustrate realistic and
large-scale software development in action. Because PyMailGUI is a
relatively large and complete program, it shows by example some of
the code structuring techniques that prove useful once we leave the
realm of the small and artificial. For instance, object-oriented
programming and modular design work well here to divide the system
in smaller, self-contained units.
Ultimately, though, PyMailGUI serves to illustrate just how far the
combination of GUIs, networking, and Python can take us. Like all Python
programs, this system is
scriptable
—once you’ve
learned its general structure, you can easily change it to work as you
like, by modifying its source code. And like all Python programs, this one
is
portable
—you can run it on any system with Python
and a network connection, without having to change its code. Such
advantages become automatic when your software is coded in an open source,
portable, and readable language like Python.
This chapter is something of
a self-study exercise. Because PyMailGUI is fairly large
and mostly applies concepts we’ve already learned, we won’t go into much
detail about its actual code. Instead, it is listed for you to read on
your own. I encourage you to study the source and comments and to run
this program live to get a feel for its operation; example save-mail
files are included so you can even experiment offline.
As you study and run this program, you’ll also want to refer back
to the modules we introduced earlier in the book and are reusing here,
to gain a full understanding of the system. For reference, here are the
major examples that will see new action in this chapter:
Server sends and receives, parsing, construction
(Client-side scripting chapter)
Thread queue management for GUI callbacks (GUI tools
chapter)
Border configuration for top-level window (GUI tools
chapter)
Text widget used in mail view windows, and in some pop ups
(GUI examples chapter)
Some of these modules in turn use additional examples we coded
earlier but that are not imported by PyMailGUI itself (textEditor
, for instance, usesguimaker
to create its windows and toolbar).
Naturally, we’ll also be coding new modules here. The following new
modules are intended to be potentially useful in other programs:
popuputil.py
Various pop-up windows, written for general use
messagecache.py
A cache manager that keeps track of mail already
loaded
wraplines.py
A utility for wrapping long lines of messages
mailconfig.py
User configuration parameters—server names, fonts, and so on
(augmented here)
html2text.py
A rudimentary parser for extracting plain text from
HTML-based emails
Finally, the following are the new major modules coded in this
chapter which are specific to the PyMailGUI program. In total, PyMailGUI
itself consists of the ten modules in this and the preceding lists,
along with a handful of less prominent source files we’ll see in this
chapter:
SharedNames.py
Program-wide globals used by multiple files
ViewWindows.py
The implementation of View, Write, Reply, and Forward
message view windows
ListWindows.py
The implementation of mail-server and local-file message
list windows
PyMailGuiHelp.py
User-oriented help text, opened by the main window’s bar
button
PyMailGui.py
The main, top-level file of the program, run to launch the
main window
As a realistically scaled system, PyMailGUI’s size is also
instructive. All told, PyMailGUI is composed of 18 new files: the 10
new Python modules in the two preceding lists, plus an HTML help file,
a small configuration file for PyEdit pop ups, a currently unused
package initialization file, and 5 short Python files in a
subdirectory used for alternate account configuration.
Together, it contains some
2,400
new lines of program source code in 16
Python files (including comments and whitespace), plus roughly 1,700
lines of help text in one Python and one HTML file (in two flavors).
This 4,100 new line total doesn’t include the four other book examples
listed in the previous section that are reused in PyMailGUI. The
reused examples themselves constitute 2,600 additional lines of Python
program code—roughly 1,000 lines each for PyEdit andmailtools
alone. That brings the grand total
to
6,700
lines: 4,100 new + 2,600
reused. Of this total,
5,000
lines
is in program code files (2,400 of which are new here) and 1,700 lines
is help text.
[
54
]
I obtained these lines counts with PyEdit’s Info pop up, and
opened the files with the code button in the PyDemos entry for this
program (the Source button in PyMailGUI’s own text-based help window
does similar work). For the break down by individual files, see the
Excel spreadsheet file
linecounts.xls
in the
media
subdirectory of PyMailGUI; this file
is also used to test attachment sends and receives, and so appears
near the end of the emails in file
SavedEmail\version30-4E
if opened in the
GUI (we’ll see how to open mail save files in a moment).
Watch for the changes section ahead for size comparisons to
prior versions. Also see the SLOC counter script in
Chapter 6
for an alternative way to count
source lines that is less manual, but can’t include all related files
in a single run and doesn’t discriminate between program code and help
text.
As these statistics probably suggest, this is the largest
example we’ll see in this book, but you shouldn’t be deterred by its
size. Because it uses modular and OOP techniques, the code is simpler
than you may think:
Python’s modules allow us to divide the system into files
that have a cohesive purpose, with minimal coupling between
them—code is easier to locate and understand if your modules have
a logical, self-contained structure.
Python’s OOP support allows us to factor code for reuse and
avoid
redundancy—
as you’ll
see, code is customized, not repeated, and the classes we will
code reflect the actual components of the GUI to make them easy to
follow.
For instance, the implementation of mail list windows is easy to
read and change, because it has been factored into a common shared
superclass, which is customized by subclasses for mail-server and
save-file lists; since these are mostly just variations on a theme,
most of the code appears in just one place. Similarly, the code that
implements the message view window is a superclass shared by write,
reply, and forward composition windows; subclasses simply tailor it
for writing rather than viewing.
Although we’ll deploy these techniques in the context of a mail
processing program here, such techniques will apply to any nontrivial
program you’ll write in Python.
To help get you started, thePyMailGuiHelp.py
module listed in part near
the end of this chapter includes a help text string that describes how
this program is used, as well as its major features. You can also view
this help live in both text and HTML form when the program is run.
Experimenting with the system, while referring to its code, is
probably the best and quickest way to uncover its
secrets.
Before we
start digging into the code of this relatively large
system, some context is in order. PyMailGUI is a Python program that
implements a client-side email processing user interface with the
standard tkinter GUI toolkit. It is presented both as an instance of
Python Internet scripting and as a realistically scaled example that
ties together other tools we’ve already seen, such as threads and
tkinter GUIs.
Like thepymail
console-based
program we wrote in
Chapter 13
, PyMailGUI
runs entirely on your local computer. Your email is fetched from and
sent to remote mail servers over sockets, but the program and its user
interface run locally. As a result, PyMailGUI is
called an email client: likepymail
, it employs Python’s client-side tools
to talk to mail servers from the local machine. Unlikepymail
, though, PyMailGUI is a full-featured
user interface: email operations are performed with point-and-click
operations and advanced mail processing such as attachments, save files,
and Internationalization is supported.
Like many examples presented in this text, PyMailGUI is a
practical, useful program. In fact, I run it on all kinds of machines to
check my email while traveling around the world teaching Python classes.
Although PyMailGUI won’t put Microsoft Outlook out of business anytime
soon, it has two key pragmatic features alluded to earlier that have
nothing to do with email itself—portability and scriptability, which are
attractive features in their own right and merit a few additional words
here:
PyMailGUI runs on any machine with sockets and a Python with
tkinter installed. Because email is transferred with the Python
libraries, any Internet connection that supports Post Office
Protocol (POP) and Simple Mail Transfer Protocol (SMTP) access
will do. Moreover, because the user interface is coded with
tkinter, PyMailGUI should work, unchanged, on Windows, the X
Window System (Unix, Linux), and the Macintosh (classic and OS X),
as long as Python 3.X runs there too.
Microsoft Outlook may be a more feature-rich package, but it
has to be run on Windows, and more specifically, on a single
Windows machine. Because it generally deletes email from a server
as it is downloaded by default and stores it on the client, you
cannot run Outlook on multiple machines without spreading your
email across all those machines. By contrast, PyMailGUI saves and
deletes email only on request, and so it is a bit friendlier to
people who check their email in an ad hoc fashion on arbitrary
computers (like me).
PyMailGUI can become anything you want it to be because it
is fully programmable. In fact, this is the real killer feature of
PyMailGUI and of open source software like Python in
general—because you have full access to PyMailGUI’s source code,
you are in complete control of where it evolves from here. You
have nowhere near as much control over commercial, closed products
like Outlook; you generally get whatever a large company decided
you need, along with whatever bugs that company might have
introduced.
As a Python script, PyMailGUI is a much more flexible tool.
For instance, we can change its layout, disable features, and add
completely new functionality quickly by changing its Python source
code. Don’t like the mail-list display? Change a few lines of code
to customize it. Want to save and delete your mail automatically
as it is loaded? Add some more code and buttons. Tired of seeing
junk mail? Add a few lines of text processing code to the load
function to filter spam. These are just a few examples. The point
is that because PyMailGUI is written in a high-level,
easy-to-maintain scripting language, such customizations are
relatively simple, and might even be fun.
At the end of the day, because of such features, this is a
realistic Python program that I actually
use
—both
as a primary email tool and as a fallback option when my ISP’s webmail
system goes down (which, as I mentioned in the prior chapter, has a way
of happening at the worst possible times).
[
55
]
Python scripting is an enabling skill to
have.