Python Windows Tutorial
Python Windows Tutorial
Tutorial Notes
These notes closely follow the slides for the tutorial and include all code samples.
21776717.doc
Table of Contents
21776717.doc
Part 1: - Fundamentals
21776717.doc
Using Python To Harness Windows
1 Background
Page 4 of 72 21776717.doc
Using Python To Harness Windows
Page 5 of 72 21776717.doc
Using Python To Harness Windows
Page 6 of 72 21776717.doc
Using Python To Harness Windows
Note: some people like to copy python.exe and pythonw.exe to their system
directory, especially on Win95/98
Page 7 of 72 21776717.doc
Using Python To Harness Windows
C:\Scripts>
You can go one further with the PATHEXT variable. To kmake it
permanent, go to Control Panel | System | Environment:
C:\Scripts>echo %PATHEXT%
.exe;.bat;.cmd
C:\Scripts>set PATHEXT=%PATHEXT%;.py
C:\Scripts>echo %PATHEXT%
.exe;.bat;.cmd;.py
C:\Scripts>hello
Hello from Python
C:\Scripts>
..and of course you can use NT’s other command line tools, like the
scheduler to run Python jobs.
Page 8 of 72 21776717.doc
Using Python To Harness Windows
Key features:
• C editor component
• Syntax coloring
• drop-down completion (as far as is possible in Python) and argument lists
• class and function browser which operates across modules
Page 9 of 72 21776717.doc
Using Python To Harness Windows
4.1 Modes
Pythonwin support a number of command line parameters:
Command Line Description
/edit filename Starts Pythonwin, and opens the named file for editing
/run filename Starts Pythonwin, and runs the specified script.
/nodde Must be the first parameter. Starts Pythonwin without DDE
support, allowing for multiple Pythonwin instances. See
Pythonwin and DDE later in this section
/app appmodule Treats the named file as a Pythonwin application. This is for
advanced users only, and is discussed in Chapter ?? GUI
Development.
For scripts that work with files, know what directory you are in!
Page 10 of 72 21776717.doc
Using Python To Harness Windows
Page 11 of 72 21776717.doc
Using Python To Harness Windows
Some nice source tools, and no doubt more to come…from the context menu:
Page 12 of 72 21776717.doc
Using Python To Harness Windows
Page 13 of 72 21776717.doc
Using Python To Harness Windows
4.9 Debugging
Page 14 of 72 21776717.doc
Using Python To Harness Windows
4.10 Grep
…leads to…
4.11 Conclusion
• evolving fast,
• extensible
• not too shabby for a free editor!
Page 15 of 72 21776717.doc
Using Python To Harness Windows
Part 2: - COM
Page 16 of 72 21776717.doc
Using Python To Harness Windows
Most big apps expose their functionality through COM servers. You can borrow
their functionality for your own programs.
Programming for Windows is like being in a sea of objects all waiting to help you.
The Registry: where COM objects find out about each other. (Not just a big INI
file!)
Page 17 of 72 21776717.doc
Using Python To Harness Windows
Page 18 of 72 21776717.doc
Using Python To Harness Windows
Page 19 of 72 21776717.doc
Using Python To Harness Windows
5.7 Transactions
Crudely, a movement of money.
All accounts must sum to zero!
Date: 01/01/1998
Multi-line
Date: 10/03/1999
Cash +117.50
Sales Category 1 -50.00
Sales Category 2 -30.00
Sales Category 3 -20.00
Sales tax on all three (owed to Customs & Excise) -17.50
Functionality:
• Store
• Edit
• Add
• Validate
• effectOn(self, account)
• Extra keys/values
• add, multiply – an algebra for financial transactions!
Page 20 of 72 21776717.doc
Using Python To Harness Windows
5.8 Accounts
Accounts form a tree – this is the “Balance Sheet”…
5.9 BookSets
A wrapper around a list of transactions.
• Load/Save with cPickle (one of Python’s killer features!)
• Import/Export ASCII text, list/dictionary/tuple structures etc.
Querying
• get history of an account
• get the ‘tree of accounts’
• get all balances on date -> Balance Sheet report
• get all changes between two dates -> Profit & Loss reports
Page 21 of 72 21776717.doc
Using Python To Harness Windows
Advanced
• map from one accounts structure to another
• analyse and trace cash flows
• Multidimensional analysis
Page 22 of 72 21776717.doc
Using Python To Harness Windows
f = open(python_filename,'wb')
cPickle.dump(self.__journal,f)
f.close()
• Wrap/Unwrap subobjects
…so a single class not the best design for real apps. Others options:
• COM Base Class, Python Server
• Pure Python Base Class, COM Subclass
• COM interface, Python Delegate
We go for option 3: Delegate. Keeps our Python package pure and portable.
Startup Code:
# comservers.py – to be expanded
class COMBookSet:
_reg_clsid_ = '{38CB8241-D698-11D2-B806-0060974AB8A9}'
_reg_progid_ = 'Doubletalk.BookServer'
_public_methods_ = ['double']
def __init__(self):
self.__BookSet = doubletalk.bookset.BookSet()
if __name__ == '__main__':
win32com.server.register.UseCommandLine(COMBookSet)
Page 23 of 72 21776717.doc
Using Python To Harness Windows
Sub InitCOMServer()
'called when the program starts
On Error GoTo InitCOMServer_error
Set BookServer = CreateObject("Doubletalk.BookServer")
Exit Sub
InitCOMServer_error:
Dim msg As String
msg = "There was an error trying to initialize the
BookServer." + _
"Please check that it is properly registered and
try the Python " + _
"test functions first. The program will now
abort."
MsgBox msg
End
End Sub
Sub CloseCOMServer()
Set BookServer = Nothing
End Sub
Sub TestCOMServer()
'just to check it is alive
Dim hopefully_four As Integer
hopefully_four = BookServer.Double(2)
MsgBox "2 x 2 = " & hopefully_four & ", so your server is
alive"
End Sub
Page 24 of 72 21776717.doc
Using Python To Harness Windows
Goal:
Date-Ordered List of Transactions
def count(self):
# return number of transactions
return len(self.__BookSet)
Page 25 of 72 21776717.doc
Using Python To Harness Windows
Screen.MousePointer = vbHourglass
lstJournal.Clear
For i = 0 To frmMain.BookServer.count - 1
trantext = frmMain.BookServer.getOneLineDescription(i)
lstJournal.AddItem trantext
Next i
Screen.MousePointer = vbDefault
Caption = "Journal view - " & lstJournal.ListCount & "
transactions"
End Sub
The Result
Page 26 of 72 21776717.doc
Using Python To Harness Windows
Created by BookSet
Dim newtran As Object
Set newtran = BookServer.CreateTransaction
newtran.setDateString "31/3/2000"
newtran.setComment "Even more royalties"
newtran.addLine "MyCo.Assets.NCA.CurAss.Cash", 5000
newtran.addLastLine "MyCo.Capital.PL.Income.Writing"
BookServer.Add newtran
The latter means less Python code, less in the registry, and less choice / more consistency for
users!
Page 27 of 72 21776717.doc
Using Python To Harness Windows
def createTransaction(self):
comTran = COMTransaction()
idTran = win32com.server.util.wrap(comTran)
return idTran
Page 28 of 72 21776717.doc
Using Python To Harness Windows
table = frmMain.BookServer.getAccountDetails(AccountName)
Page 29 of 72 21776717.doc
Using Python To Harness Windows
Page 30 of 72 21776717.doc
Using Python To Harness Windows
5.21 Conclusions
Page 31 of 72 21776717.doc
Using Python To Harness Windows
Page 32 of 72 21776717.doc
Using Python To Harness Windows
Page 33 of 72 21776717.doc
Using Python To Harness Windows
Our plan
• give the COMBookSet a write() method
• ways to start trapping output, end trapping it, and retrieve any available
output.
• Keep it in a list of strings
Implementation
def beginTrappingOutput(self): # exposed as public method
self.outputBuffer = []
self.old_output = sys.stdout
sys.stdout = self
Page 34 of 72 21776717.doc
Using Python To Harness Windows
Executing Scripts:
• Menu option to run a script
• exec(expression, [globals[, locals]]) does the work in one line.
Importing Scripts
• Python imp module exposes import mechanism; need to grab the module
object and add it to our namespace.
• Add an importFile() method to COMBookSet
Reload option
• Useful for users, and for us! Closes and reloads BookServer.
Page 35 of 72 21776717.doc
Using Python To Harness Windows
Page 36 of 72 21776717.doc
Using Python To Harness Windows
Page 37 of 72 21776717.doc
Using Python To Harness Windows
Front End
Maintain a list of modules and class names. Short chunk of Python passed to
interpretString() to instantiate them.
Page 38 of 72 21776717.doc
Using Python To Harness Windows
This goes beyond normal Windows development and into an area which is one
of Python’s greatest strengths – extensibility.
This kind of extensible app would be prohibitively expensive and difficult without
Python. Macro languages are normally only available to Microsoft, Visio et al.
With Python it is straightforward.
Page 39 of 72 21776717.doc
Using Python To Harness Windows
Why Excel?
• Very widely used in financial and scientific circles.
• Key source and destination for numeric data.
Starting up Excel
>>> from win32com.client import Dispatch
>>> xlApp = Dispatch("Excel.Application")
>>> xlApp.Visible = 1
>>> xlApp.Workbooks.Add()
<win32com.gen_py.Microsoft Excel 8.0 Object Library.Workbook>
>>>
Page 40 of 72 21776717.doc
Using Python To Harness Windows
Page 41 of 72 21776717.doc
Using Python To Harness Windows
Page 42 of 72 21776717.doc
Using Python To Harness Windows
Keyword Arguments
Excel likes these a lot:
expression.SaveAs(Filename, FileFormat, Password,
WriteResPassword, ReadOnlyRecommended,
CreateBackup, AddToMru, TextCodePage,
TextVisualLayout)
Supply what you need:
>>> xlBook.SaveAs(Filename='C:\\temp\\mysheet.xls')
>>>
Watch the capitalisation! Microsoft are not always 100% consistent.
Page 43 of 72 21776717.doc
Using Python To Harness Windows
Horizontal range:
>>> xlSheet.Range('C3:E3').Value
((L'left', L'to', L'right'),)
>>>
Vertical Range
>>> xlSheet.Range('F2:F4').Value
((1.0,), (2.0,), (3.0,))
>>>
Passing arrays is FAST – 60 columns, 100 rows in an eyeblink!
Page 44 of 72 21776717.doc
Using Python To Harness Windows
Page 45 of 72 21776717.doc
Using Python To Harness Windows
8 Automating Word
def simple():
myWord = Dispatch('Word.Application')
myWord.Visible = 1 # comment out for production
myDoc = myWord.Documents.Add()
myRange = myDoc.Range(0,0)
myRange.InsertBefore('Hello from Python!')
Page 46 of 72 21776717.doc
Using Python To Harness Windows
def show(self):
# convenience when developing
self.wordApp.Visible = 1
Page 47 of 72 21776717.doc
Using Python To Harness Windows
def printout(self):
self.wordDoc.PrintOut()
Adding text
Move the selection to the end, and insert into selection
def selectEnd(self):
# ensures insertion point is at the end of the document
self.wordSel.Collapse(0)
# 0 is the constant wdCollapseEnd; don't want to depend
# on makepy support.
Page 48 of 72 21776717.doc
Using Python To Harness Windows
Styles and templates together give a very easy way to build up a sophisticated
document.
Adding Tables
Let’s be lazy and use AutoFormat – saves a lot of code: Fortunately, most
arguments are optional!
Table.AutoFormat(Format, ApplyBorders, ApplyShading,
ApplyFont, ApplyColor, ApplyHeadingRows, ApplyLastRow,
ApplyFirstColumn, ApplyLastColumn, AutoFit)
Create a block of tab-delimited text, then ask Word to turn it into a table:
def addTable(self, table, styleid=None):
# Takes a 'list of lists' of data.
# first we format the text. You might want to preformat
# numbers with the right decimal places etc. first.
textlines = []
for row in table:
textrow = map(str, row) #convert to strings
textline = string.join(textrow, '\t')
textlines.append(textline)
text = string.join(textlines, '\n')
#convert to a table
wordTable = self.wordSel.ConvertToTable(Separator='\t')
#and format
if styleid:
wordTable.AutoFormat(Format=styleid)
Page 49 of 72 21776717.doc
Using Python To Harness Windows
Page 50 of 72 21776717.doc
Using Python To Harness Windows
TaDa!
Page 51 of 72 21776717.doc
Using Python To Harness Windows
Page 52 of 72 21776717.doc
Using Python To Harness Windows
Goal:
Our BookServer running in the back office, VB clients elsewhere
Configuration
DCOM needs to be enabled on the remote server. Choose Start > Run and
enter DCOMCNFG.EXE. A configuration dialog starts up. Select the Default
Properties tab and check the box for Enable Distributed COM on this computer.
Implementation
Visual Basic startup code needs one extra argument
Set BookServer = CreateObject("Doubletalk.BookServer",
RemoteMachine)
That’s all!
…apart from Singletons, threads etc. – need to ensure multiple clients reach the
same server instance, simultaneous clients don’t create a problem etc. Read the
book!
Page 53 of 72 21776717.doc
Using Python To Harness Windows
Part 3: - Cookbook
Page 54 of 72 21776717.doc
Using Python To Harness Windows
10 Database Access
DAO & Jet COM object model for manipulating Access databases. ODBC
support grafted on later, but not designed for client-server use.
Used by the infamous Data Control in VB.
We will look at ODBC for client-server work, and DAO/ADO for getting at Access
databases.
1
Great Big Five Letter Acronyms
Page 55 of 72 21776717.doc
Using Python To Harness Windows
Recommendations:
• ODBC module in Pythonwin for occasional use
• mxODBC for regular database work,
• Sam Rushing’s library if you love the raw ODBC API
Page 56 of 72 21776717.doc
Using Python To Harness Windows
10.5 mxDateTime
>>> import DateTime
>>> DateTime.DateTimeFromCOMDate(0) # the Microsoft system
1899-12-30 00:00:00.00
>>> aDateTime.COMDate() # convert to Microsoft COM/Excel
dates
36265.0
>>>
>>> DateTime.now() - aDateTime # RelativeDateTime object
<DateTimeDelta object for '16:23:40:16.18' at 1106530>
>>> aDateTime + DateTime.RelativeDateTime(months=+3)
1999-07-15 00:00:00.00
>>> # first of next month...
>>> aDateTime + DateTime.RelativeDateTime(months=+1,day=1)
1999-05-01 00:00:00.00
>>> DateTime.now()
1999-05-01 23:42:20.15
>>> DateTime.Feasts.EasterSunday(2001)
2001-04-15 00:00:00.00
>>> DateTime.Parser.DateFromString('Friday 19th October 1987')
1987-10-19 00:00:00.00
>>>
Databases are full of dates. This is really useful.
Page 57 of 72 21776717.doc
Using Python To Harness Windows
SLOW: Cursor.execute(operation)
cursor.execute("""INSERT INTO analysis
(tranid, trandate, account, amount) VALUES
(1, {d '1999-12-31 23:59:59'}, 'Cash',100.00)""")
FASTER: Cursor.execute(operation[,parameters])
cursor.execute("""INSERT INTO analysis
(tranid, trandate, account, amount)
VALUES (?,?,?,?)""", (2, aDate, 'Cash', 117.50))
FASTEST: Cursor.executemany(operation,seq_of_parameters)
cursor.execute("""INSERT INTO analysis
(tranid, trandate, account, amount)
VALUES (?,?,?,?)""", [
(2, aDate, 'Cash', 117.50)
(3, aDate, 'Shares', -117.50)
# and so on
])
More importantly, parsing SQL takes memory on the server. Apps using
prepared ones can support many more users while maintaining performance.
Benchmarking
accessdemo/slow: 141.643058/second
accessdemo/faster: 117.619382/second
accessdemo/fastest: 148.148148/second
asademo/slow: 292.825772/second
asademo/faster: 426.621164/second
asademo/fastest: 528.262016/second
Jet raw SQL inserts: 113.352981/second
Jet AddNew/Delete: 186.985792/second
Conclusions:
(1) Access doesn’t know about prepared statements and is best accessed
through DAO
(2) SQL databases are faster
(3) SQL databases go 80% faster with prepared statements
Page 58 of 72 21776717.doc
Using Python To Harness Windows
Connecting
>>> import win32com.client
>>> daoEngine = win32com.client.Dispatch('DAO.DBEngine')
>>> daoDB = daoEngine.OpenDatabase('C:\\MYDIR\\pydbdemos.mdb')
>>> daoRS = daoDB.OpenRecordset('SELECT ClientID, InvoiceDate,
\
Consultant, Hours FROM Invoices')
Page 59 of 72 21776717.doc
Using Python To Harness Windows
Page 60 of 72 21776717.doc
Using Python To Harness Windows
Page 61 of 72 21776717.doc
Using Python To Harness Windows
11 Communications
• Serial I/O
• Remote Access
• Sockets
Page 62 of 72 21776717.doc
Using Python To Harness Windows
Page 63 of 72 21776717.doc
Using Python To Harness Windows
12 System Administration
User Names:
>>> import win32api
>>> userName=win32api.GetUserName()
User Info:
Windows API structs exposed as editable dictionaries (if you have permission)
>>> import win32net
>>> info=win32net.NetUserGetInfo(None, userName, 1)
>>> print info['name'] # print just the user name
skip
>>> dump(info)
priv = 2
home_dir = c:\winnt\profiles\skip\personal
password = None
script_path =
name = skip
flags = 66049
password_age = 23792806
comment =
>>>
This is level 1 – others levels offer around 30 pieces of information.
Adding Users
>>> d={}
>>> d['name'] = "PythonTestUser"
>>> d['password'] = "Top Secret"
>>> d['comment'] = "A user created by some Python demo code"
>>> d['flags'] = win32netcon.UF_NORMAL_ACCOUNT |
win32netcon.UF_SCRIPT
>>> d['priv'] = win32netcon.USER_PRIV_USER
>>> win32net.NetUserAdd(None, 1, d)
>>>
We said the dictionaries were editable…
What else?
Similar functions for working with
• groups
• servers
• network shares (e.g. create users and their shares in bulk)
• rebooting the system
Page 64 of 72 21776717.doc
Using Python To Harness Windows
13 Active Scripting
Lets you embed any scripting language using COM.
Use Python in
• Internet Information Server
• Internet Explorer
• Windows Scripting Host
But how many people’s browsers can you count on to have Python set up?
<%
# Save the URL into a local variable
url = Request.ServerVariables("PATH_INFO")
%>
<H2>Current Document</H2>
The URL to this file is <pre><%= url %></pre><p>
The local path to this URL is <pre><%= Server.mappath(url)
%></pre>
Page 65 of 72 21776717.doc
Using Python To Harness Windows
# wsh.pys
# A Windows Scripting Host file that uses Python.
net = WScript.CreateObject("Wscript.Network")
netInfo = net.EnumNetworkDrives()
WScript.Echo(netInfo[0], "=", netInfo[1])
You can also access these objects from ordinary Python scripts.
Page 66 of 72 21776717.doc
Using Python To Harness Windows
14 GUI Development
Options:
• Tkinter
• WxWindows
• PythonWin
• Embed via COM
• Embed at C level (C++, Delphi)
Page 67 of 72 21776717.doc
Using Python To Harness Windows
14.3 wxWindows
Cross-platform, but based on heavily on Windows.
Page 68 of 72 21776717.doc
Using Python To Harness Windows
15 Delphi
C-Level API.
Python wrapped up as Pascal module
Python VCL components make it much easier than embedding in a C++ app.
Page 69 of 72 21776717.doc
Using Python To Harness Windows
Page 70 of 72 21776717.doc
Using Python To Harness Windows
win32print Interface to the printerrelated Windows APIs.
win32process Interface to the process related Windows APIs. This is discussed in
detail in Chapter 17, Files and Processes.
win32ras Interface to the Windows Remote Access Service (RAS). Used for
establishing remote connections to Windows NT Servers, typically
using a modem.
win32security Access to the Windows NT security related functions.
win32service Access to the Windows NT Servicesrelated API. This is discussed
win32serviceutil in detail in Chapter 18, Windows NT Services.
win32trace Debugging related modules. These modules allow you to collect the
win32traceutil output of a Python process in a separate process. This is most useful
when debugging serverstyle applications, where Python error and
other messages are not available.
16.2 CallDLL/WinDLL
www.nightmare.com
Tiny (14k) Python extension giving you pointers, memory buffers, LoadLibrary()
and GetProcAddress().
Windll wraps it up nicely: call any DLL!
>>> from dynwin.windll import *
>>> mod1 = module('c:\\temp\\simple') # loads the DLL
>>> mod1.handle # it can report its location in memory
22806528
>>> mod1.Min(27, 28) # loads and executes Min function
27
>>> mod1.Min # we now have a 'callable function'
object...
<callable function "Min">
>>> mod1.Min.address #...which knows its address too
22836704
Of course, this also gives you the ability to crash, unlike a well-made Python
extension.
Page 71 of 72 21776717.doc
Using Python To Harness Windows
The End
Page 72 of 72 21776717.doc