mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-20 21:33:13 -07:00
Remove vendored pywin32
This commit is contained in:
parent
a827c8700b
commit
54422992a4
590 changed files with 6 additions and 100762 deletions
|
@ -17,6 +17,12 @@ import libs.util
|
|||
if not libs.autoload.completed:
|
||||
sys.exit('Could not load vendored libraries.')
|
||||
|
||||
try:
|
||||
import win32event
|
||||
except ImportError:
|
||||
if sys.platform == 'win32':
|
||||
sys.ext('Please install pywin32')
|
||||
|
||||
PROGRAM_DIR = libs.util.module_root()
|
||||
|
||||
# init preliminaries
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
jaraco-windows
|
||||
pywin32
|
||||
|
|
Binary file not shown.
|
@ -1,56 +0,0 @@
|
|||
"""adodbapi - A python DB API 2.0 (PEP 249) interface to Microsoft ADO
|
||||
|
||||
Copyright (C) 2002 Henrik Ekelund, version 2.1 by Vernon Cole
|
||||
* http://sourceforge.net/projects/adodbapi
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
|
||||
if sys.version_info < (3,0): # in Python 2, define all symbols, just like the bad old way
|
||||
from apibase import *
|
||||
VariantConversionMap = MultiMap # old name. Should use apibase.MultiMap
|
||||
from .ado_consts import *
|
||||
_makeByteBuffer = buffer
|
||||
else:
|
||||
# but if the user is running Python 3, then keep the dictionary clean
|
||||
from .apibase import apilevel, threadsafety, paramstyle
|
||||
from .apibase import Warning, Error, InterfaceError, DatabaseError, DataError, OperationalError, IntegrityError
|
||||
from .apibase import InternalError, ProgrammingError, NotSupportedError, FetchFailedError
|
||||
from .apibase import NUMBER, STRING, BINARY, DATETIME, ROWID
|
||||
_makeByteBuffer = bytes
|
||||
|
||||
from .adodbapi import connect, Connection, __version__, dateconverter, Cursor
|
||||
|
||||
def Binary(aString):
|
||||
"""This function constructs an object capable of holding a binary (long) string value. """
|
||||
return _makeByteBuffer(aString)
|
||||
|
||||
def Date(year,month,day):
|
||||
"This function constructs an object holding a date value. "
|
||||
return dateconverter.Date(year,month,day)
|
||||
|
||||
def Time(hour,minute,second):
|
||||
"This function constructs an object holding a time value. "
|
||||
return dateconverter.Time(hour,minute,second)
|
||||
|
||||
def Timestamp(year,month,day,hour,minute,second):
|
||||
"This function constructs an object holding a time stamp value. "
|
||||
return dateconverter.Timestamp(year,month,day,hour,minute,second)
|
||||
|
||||
def DateFromTicks(ticks):
|
||||
"""This function constructs an object holding a date value from the given ticks value
|
||||
(number of seconds since the epoch; see the documentation of the standard Python time module for details). """
|
||||
return Date(*time.gmtime(ticks)[:3])
|
||||
|
||||
def TimeFromTicks(ticks):
|
||||
"""This function constructs an object holding a time value from the given ticks value
|
||||
(number of seconds since the epoch; see the documentation of the standard Python time module for details). """
|
||||
return Time(*time.gmtime(ticks)[3:6])
|
||||
|
||||
def TimestampFromTicks(ticks):
|
||||
"""This function constructs an object holding a time stamp value from the given
|
||||
ticks value (number of seconds since the epoch;
|
||||
see the documentation of the standard Python time module for details). """
|
||||
return Timestamp(*time.gmtime(ticks)[:6])
|
||||
|
||||
version = 'adodbapi v' + __version__
|
|
@ -1,276 +0,0 @@
|
|||
# ADO enumerated constants documented on MSDN:
|
||||
# http://msdn.microsoft.com/en-us/library/ms678353(VS.85).aspx
|
||||
|
||||
# IsolationLevelEnum
|
||||
adXactUnspecified = -1
|
||||
adXactBrowse = 0x100
|
||||
adXactChaos = 0x10
|
||||
adXactCursorStability = 0x1000
|
||||
adXactIsolated = 0x100000
|
||||
adXactReadCommitted = 0x1000
|
||||
adXactReadUncommitted = 0x100
|
||||
adXactRepeatableRead = 0x10000
|
||||
adXactSerializable = 0x100000
|
||||
|
||||
# CursorLocationEnum
|
||||
adUseClient = 3
|
||||
adUseServer = 2
|
||||
|
||||
# CursorTypeEnum
|
||||
adOpenDynamic = 2
|
||||
adOpenForwardOnly = 0
|
||||
adOpenKeyset = 1
|
||||
adOpenStatic = 3
|
||||
adOpenUnspecified = -1
|
||||
|
||||
# CommandTypeEnum
|
||||
adCmdText = 1
|
||||
adCmdStoredProc = 4
|
||||
adSchemaTables = 20
|
||||
|
||||
# ParameterDirectionEnum
|
||||
adParamInput = 1
|
||||
adParamInputOutput = 3
|
||||
adParamOutput = 2
|
||||
adParamReturnValue = 4
|
||||
adParamUnknown = 0
|
||||
directions = {
|
||||
0: 'Unknown',
|
||||
1: 'Input',
|
||||
2: 'Output',
|
||||
3: 'InputOutput',
|
||||
4: 'Return',
|
||||
}
|
||||
def ado_direction_name(ado_dir):
|
||||
try:
|
||||
return 'adParam' + directions[ado_dir]
|
||||
except:
|
||||
return 'unknown direction ('+str(ado_dir)+')'
|
||||
|
||||
# ObjectStateEnum
|
||||
adStateClosed = 0
|
||||
adStateOpen = 1
|
||||
adStateConnecting = 2
|
||||
adStateExecuting = 4
|
||||
adStateFetching = 8
|
||||
|
||||
# FieldAttributeEnum
|
||||
adFldMayBeNull = 0x40
|
||||
|
||||
# ConnectModeEnum
|
||||
adModeUnknown = 0
|
||||
adModeRead = 1
|
||||
adModeWrite = 2
|
||||
adModeReadWrite = 3
|
||||
adModeShareDenyRead = 4
|
||||
adModeShareDenyWrite = 8
|
||||
adModeShareExclusive = 12
|
||||
adModeShareDenyNone = 16
|
||||
adModeRecursive = 0x400000
|
||||
|
||||
# XactAttributeEnum
|
||||
adXactCommitRetaining = 131072
|
||||
adXactAbortRetaining = 262144
|
||||
|
||||
ado_error_TIMEOUT = -2147217871
|
||||
|
||||
# DataTypeEnum - ADO Data types documented at:
|
||||
# http://msdn2.microsoft.com/en-us/library/ms675318.aspx
|
||||
adArray = 0x2000
|
||||
adEmpty = 0x0
|
||||
adBSTR = 0x8
|
||||
adBigInt = 0x14
|
||||
adBinary = 0x80
|
||||
adBoolean = 0xb
|
||||
adChapter = 0x88
|
||||
adChar = 0x81
|
||||
adCurrency = 0x6
|
||||
adDBDate = 0x85
|
||||
adDBTime = 0x86
|
||||
adDBTimeStamp = 0x87
|
||||
adDate = 0x7
|
||||
adDecimal = 0xe
|
||||
adDouble = 0x5
|
||||
adError = 0xa
|
||||
adFileTime = 0x40
|
||||
adGUID = 0x48
|
||||
adIDispatch = 0x9
|
||||
adIUnknown = 0xd
|
||||
adInteger = 0x3
|
||||
adLongVarBinary = 0xcd
|
||||
adLongVarChar = 0xc9
|
||||
adLongVarWChar = 0xcb
|
||||
adNumeric = 0x83
|
||||
adPropVariant = 0x8a
|
||||
adSingle = 0x4
|
||||
adSmallInt = 0x2
|
||||
adTinyInt = 0x10
|
||||
adUnsignedBigInt = 0x15
|
||||
adUnsignedInt = 0x13
|
||||
adUnsignedSmallInt = 0x12
|
||||
adUnsignedTinyInt = 0x11
|
||||
adUserDefined = 0x84
|
||||
adVarBinary = 0xCC
|
||||
adVarChar = 0xC8
|
||||
adVarNumeric = 0x8B
|
||||
adVarWChar = 0xCA
|
||||
adVariant = 0xC
|
||||
adWChar = 0x82
|
||||
# Additional constants used by introspection but not ADO itself
|
||||
AUTO_FIELD_MARKER = -1000
|
||||
|
||||
adTypeNames = {
|
||||
adBSTR: 'adBSTR',
|
||||
adBigInt: 'adBigInt',
|
||||
adBinary: 'adBinary',
|
||||
adBoolean: 'adBoolean',
|
||||
adChapter: 'adChapter',
|
||||
adChar: 'adChar',
|
||||
adCurrency: 'adCurrency',
|
||||
adDBDate: 'adDBDate',
|
||||
adDBTime: 'adDBTime',
|
||||
adDBTimeStamp: 'adDBTimeStamp',
|
||||
adDate: 'adDate',
|
||||
adDecimal: 'adDecimal',
|
||||
adDouble: 'adDouble',
|
||||
adEmpty: 'adEmpty',
|
||||
adError: 'adError',
|
||||
adFileTime: 'adFileTime',
|
||||
adGUID: 'adGUID',
|
||||
adIDispatch: 'adIDispatch',
|
||||
adIUnknown: 'adIUnknown',
|
||||
adInteger: 'adInteger',
|
||||
adLongVarBinary: 'adLongVarBinary',
|
||||
adLongVarChar: 'adLongVarChar',
|
||||
adLongVarWChar: 'adLongVarWChar',
|
||||
adNumeric: 'adNumeric',
|
||||
adPropVariant: 'adPropVariant',
|
||||
adSingle: 'adSingle',
|
||||
adSmallInt: 'adSmallInt',
|
||||
adTinyInt: 'adTinyInt',
|
||||
adUnsignedBigInt: 'adUnsignedBigInt',
|
||||
adUnsignedInt: 'adUnsignedInt',
|
||||
adUnsignedSmallInt: 'adUnsignedSmallInt',
|
||||
adUnsignedTinyInt: 'adUnsignedTinyInt',
|
||||
adUserDefined: 'adUserDefined',
|
||||
adVarBinary: 'adVarBinary',
|
||||
adVarChar: 'adVarChar',
|
||||
adVarNumeric: 'adVarNumeric',
|
||||
adVarWChar: 'adVarWChar',
|
||||
adVariant: 'adVariant',
|
||||
adWChar: 'adWChar',
|
||||
}
|
||||
|
||||
def ado_type_name(ado_type):
|
||||
return adTypeNames.get(ado_type, 'unknown type ('+str(ado_type)+')')
|
||||
|
||||
# here in decimal, sorted by value
|
||||
#adEmpty 0 Specifies no value (DBTYPE_EMPTY).
|
||||
#adSmallInt 2 Indicates a two-byte signed integer (DBTYPE_I2).
|
||||
#adInteger 3 Indicates a four-byte signed integer (DBTYPE_I4).
|
||||
#adSingle 4 Indicates a single-precision floating-point value (DBTYPE_R4).
|
||||
#adDouble 5 Indicates a double-precision floating-point value (DBTYPE_R8).
|
||||
#adCurrency 6 Indicates a currency value (DBTYPE_CY). Currency is a fixed-point number
|
||||
# with four digits to the right of the decimal point. It is stored in an eight-byte signed integer scaled by 10,000.
|
||||
#adDate 7 Indicates a date value (DBTYPE_DATE). A date is stored as a double, the whole part of which is
|
||||
# the number of days since December 30, 1899, and the fractional part of which is the fraction of a day.
|
||||
#adBSTR 8 Indicates a null-terminated character string (Unicode) (DBTYPE_BSTR).
|
||||
#adIDispatch 9 Indicates a pointer to an IDispatch interface on a COM object (DBTYPE_IDISPATCH).
|
||||
#adError 10 Indicates a 32-bit error code (DBTYPE_ERROR).
|
||||
#adBoolean 11 Indicates a boolean value (DBTYPE_BOOL).
|
||||
#adVariant 12 Indicates an Automation Variant (DBTYPE_VARIANT).
|
||||
#adIUnknown 13 Indicates a pointer to an IUnknown interface on a COM object (DBTYPE_IUNKNOWN).
|
||||
#adDecimal 14 Indicates an exact numeric value with a fixed precision and scale (DBTYPE_DECIMAL).
|
||||
#adTinyInt 16 Indicates a one-byte signed integer (DBTYPE_I1).
|
||||
#adUnsignedTinyInt 17 Indicates a one-byte unsigned integer (DBTYPE_UI1).
|
||||
#adUnsignedSmallInt 18 Indicates a two-byte unsigned integer (DBTYPE_UI2).
|
||||
#adUnsignedInt 19 Indicates a four-byte unsigned integer (DBTYPE_UI4).
|
||||
#adBigInt 20 Indicates an eight-byte signed integer (DBTYPE_I8).
|
||||
#adUnsignedBigInt 21 Indicates an eight-byte unsigned integer (DBTYPE_UI8).
|
||||
#adFileTime 64 Indicates a 64-bit value representing the number of 100-nanosecond intervals since
|
||||
# January 1, 1601 (DBTYPE_FILETIME).
|
||||
#adGUID 72 Indicates a globally unique identifier (GUID) (DBTYPE_GUID).
|
||||
#adBinary 128 Indicates a binary value (DBTYPE_BYTES).
|
||||
#adChar 129 Indicates a string value (DBTYPE_STR).
|
||||
#adWChar 130 Indicates a null-terminated Unicode character string (DBTYPE_WSTR).
|
||||
#adNumeric 131 Indicates an exact numeric value with a fixed precision and scale (DBTYPE_NUMERIC).
|
||||
# adUserDefined 132 Indicates a user-defined variable (DBTYPE_UDT).
|
||||
#adUserDefined 132 Indicates a user-defined variable (DBTYPE_UDT).
|
||||
#adDBDate 133 Indicates a date value (yyyymmdd) (DBTYPE_DBDATE).
|
||||
#adDBTime 134 Indicates a time value (hhmmss) (DBTYPE_DBTIME).
|
||||
#adDBTimeStamp 135 Indicates a date/time stamp (yyyymmddhhmmss plus a fraction in billionths) (DBTYPE_DBTIMESTAMP).
|
||||
#adChapter 136 Indicates a four-byte chapter value that identifies rows in a child rowset (DBTYPE_HCHAPTER).
|
||||
#adPropVariant 138 Indicates an Automation PROPVARIANT (DBTYPE_PROP_VARIANT).
|
||||
#adVarNumeric 139 Indicates a numeric value (Parameter object only).
|
||||
#adVarChar 200 Indicates a string value (Parameter object only).
|
||||
#adLongVarChar 201 Indicates a long string value (Parameter object only).
|
||||
#adVarWChar 202 Indicates a null-terminated Unicode character string (Parameter object only).
|
||||
#adLongVarWChar 203 Indicates a long null-terminated Unicode string value (Parameter object only).
|
||||
#adVarBinary 204 Indicates a binary value (Parameter object only).
|
||||
#adLongVarBinary 205 Indicates a long binary value (Parameter object only).
|
||||
#adArray (Does not apply to ADOX.) 0x2000 A flag value, always combined with another data type constant,
|
||||
# that indicates an array of that other data type.
|
||||
|
||||
# Error codes to names
|
||||
adoErrors= {
|
||||
0xe7b :'adErrBoundToCommand',
|
||||
0xe94 :'adErrCannotComplete',
|
||||
0xea4 :'adErrCantChangeConnection',
|
||||
0xc94 :'adErrCantChangeProvider',
|
||||
0xe8c :'adErrCantConvertvalue',
|
||||
0xe8d :'adErrCantCreate',
|
||||
0xea3 :'adErrCatalogNotSet',
|
||||
0xe8e :'adErrColumnNotOnThisRow',
|
||||
0xd5d :'adErrDataConversion',
|
||||
0xe89 :'adErrDataOverflow',
|
||||
0xe9a :'adErrDelResOutOfScope',
|
||||
0xea6 :'adErrDenyNotSupported',
|
||||
0xea7 :'adErrDenyTypeNotSupported',
|
||||
0xcb3 :'adErrFeatureNotAvailable',
|
||||
0xea5 :'adErrFieldsUpdateFailed',
|
||||
0xc93 :'adErrIllegalOperation',
|
||||
0xcae :'adErrInTransaction',
|
||||
0xe87 :'adErrIntegrityViolation',
|
||||
0xbb9 :'adErrInvalidArgument',
|
||||
0xe7d :'adErrInvalidConnection',
|
||||
0xe7c :'adErrInvalidParamInfo',
|
||||
0xe82 :'adErrInvalidTransaction',
|
||||
0xe91 :'adErrInvalidURL',
|
||||
0xcc1 :'adErrItemNotFound',
|
||||
0xbcd :'adErrNoCurrentRecord',
|
||||
0xe83 :'adErrNotExecuting',
|
||||
0xe7e :'adErrNotReentrant',
|
||||
0xe78 :'adErrObjectClosed',
|
||||
0xd27 :'adErrObjectInCollection',
|
||||
0xd5c :'adErrObjectNotSet',
|
||||
0xe79 :'adErrObjectOpen',
|
||||
0xbba :'adErrOpeningFile',
|
||||
0xe80 :'adErrOperationCancelled',
|
||||
0xe96 :'adErrOutOfSpace',
|
||||
0xe88 :'adErrPermissionDenied',
|
||||
0xe9e :'adErrPropConflicting',
|
||||
0xe9b :'adErrPropInvalidColumn',
|
||||
0xe9c :'adErrPropInvalidOption',
|
||||
0xe9d :'adErrPropInvalidValue',
|
||||
0xe9f :'adErrPropNotAllSettable',
|
||||
0xea0 :'adErrPropNotSet',
|
||||
0xea1 :'adErrPropNotSettable',
|
||||
0xea2 :'adErrPropNotSupported',
|
||||
0xbb8 :'adErrProviderFailed',
|
||||
0xe7a :'adErrProviderNotFound',
|
||||
0xbbb :'adErrReadFile',
|
||||
0xe93 :'adErrResourceExists',
|
||||
0xe92 :'adErrResourceLocked',
|
||||
0xe97 :'adErrResourceOutOfScope',
|
||||
0xe8a :'adErrSchemaViolation',
|
||||
0xe8b :'adErrSignMismatch',
|
||||
0xe81 :'adErrStillConnecting',
|
||||
0xe7f :'adErrStillExecuting',
|
||||
0xe90 :'adErrTreePermissionDenied',
|
||||
0xe8f :'adErrURLDoesNotExist',
|
||||
0xe99 :'adErrURLNamedRowDoesNotExist',
|
||||
0xe98 :'adErrUnavailable',
|
||||
0xe84 :'adErrUnsafeOperation',
|
||||
0xe95 :'adErrVolumeNotFound',
|
||||
0xbbc :'adErrWriteFile'
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,70 +0,0 @@
|
|||
""" db_print.py -- a simple demo for ADO database reads."""
|
||||
from __future__ import with_statement #needed for Python 2.5
|
||||
|
||||
import sys
|
||||
import adodbapi.ado_consts as adc
|
||||
|
||||
cmd_args = ('proxy_host', 'proxy_port', 'filename', 'table_name')
|
||||
if 'help' in sys.argv:
|
||||
print(('possible settings keywords are:',cmd_args))
|
||||
sys.exit()
|
||||
|
||||
kw_args = {} # pick up filename and proxy address from command line (optionally)
|
||||
for arg in sys.argv:
|
||||
s = arg.split("=")
|
||||
if len(s) > 1:
|
||||
if s[0] in cmd_args:
|
||||
kw_args[s[0]] = s[1]
|
||||
|
||||
kw_args.setdefault('filename', "test.mdb") # assumes server is running from examples folder
|
||||
kw_args.setdefault('table_name', 'Products') # the name of the demo table
|
||||
|
||||
# the server needs to select the provider based on his Python installation
|
||||
provider_switch = ['provider', 'Microsoft.ACE.OLEDB.12.0', "Microsoft.Jet.OLEDB.4.0"]
|
||||
|
||||
# ------------------------ START HERE -------------------------------------
|
||||
#create the connection
|
||||
constr = "Provider=%(provider)s;Data Source=%(filename)s"
|
||||
if 'proxy_host' in kw_args:
|
||||
import adodbapi.remote as db
|
||||
else:
|
||||
import adodbapi as db
|
||||
con = db.connect(constr, kw_args, macro_is64bit=provider_switch)
|
||||
|
||||
if kw_args['table_name'] == '?':
|
||||
print('The tables in your database are:')
|
||||
for name in con.get_table_names():
|
||||
print(name)
|
||||
else:
|
||||
#make a cursor on the connection
|
||||
with con.cursor() as c:
|
||||
|
||||
#run an SQL statement on the cursor
|
||||
sql = 'select * from %s' % kw_args['table_name']
|
||||
print(('performing query="%s"' % sql))
|
||||
c.execute(sql)
|
||||
|
||||
#check the results
|
||||
print(('result rowcount shows as= %d. (Note: -1 means "not known")' \
|
||||
% (c.rowcount,)))
|
||||
print('')
|
||||
print('result data description is:')
|
||||
print(' NAME Type DispSize IntrnlSz Prec Scale Null?')
|
||||
for d in c.description:
|
||||
print((('%16s %-12s %8s %8d %4d %5d %s') % \
|
||||
(d[0], adc.adTypeNames[d[1]], d[2], d[3], d[4],d[5], bool(d[6]))))
|
||||
print('')
|
||||
print('str() of first five records are...')
|
||||
|
||||
#get the results
|
||||
db = c.fetchmany(5)
|
||||
|
||||
#print them
|
||||
for rec in db:
|
||||
print(rec)
|
||||
|
||||
print('')
|
||||
print('repr() of next row is...')
|
||||
print((repr(c.fetchone())))
|
||||
print('')
|
||||
con.close()
|
|
@ -1,19 +0,0 @@
|
|||
""" db_table_names.py -- a simple demo for ADO database table listing."""
|
||||
import sys
|
||||
import adodbapi
|
||||
|
||||
try:
|
||||
databasename = sys.argv[1]
|
||||
except IndexError:
|
||||
databasename = "test.mdb"
|
||||
|
||||
provider = ['prv', "Microsoft.ACE.OLEDB.12.0", "Microsoft.Jet.OLEDB.4.0"]
|
||||
constr = "Provider=%(prv)s;Data Source=%(db)s"
|
||||
|
||||
#create the connection
|
||||
con = adodbapi.connect(constr, db=databasename, macro_is64bit=provider)
|
||||
|
||||
print(('Table names in= %s' % databasename))
|
||||
|
||||
for table in con.get_table_names():
|
||||
print(table)
|
|
@ -1,38 +0,0 @@
|
|||
import sys
|
||||
import adodbapi
|
||||
try:
|
||||
import adodbapi.is64bit as is64bit
|
||||
is64 = is64bit.Python()
|
||||
except ImportError:
|
||||
is64 = False
|
||||
|
||||
if is64:
|
||||
driver = "Microsoft.ACE.OLEDB.12.0"
|
||||
else:
|
||||
driver = "Microsoft.Jet.OLEDB.4.0"
|
||||
extended = 'Extended Properties="Excel 8.0;HDR=Yes;IMEX=1;"'
|
||||
|
||||
try: # first command line argument will be xls file name -- default to the one written by xls_write.py
|
||||
filename = sys.argv[1]
|
||||
except IndexError:
|
||||
filename = 'xx.xls'
|
||||
|
||||
constr = "Provider=%s;Data Source=%s;%s" % (driver, filename, extended)
|
||||
|
||||
conn = adodbapi.connect(constr)
|
||||
|
||||
try: # second command line argument will be worksheet name -- default to first worksheet
|
||||
sheet = sys.argv[2]
|
||||
except IndexError:
|
||||
# use ADO feature to get the name of the first worksheet
|
||||
sheet = conn.get_table_names()[0]
|
||||
|
||||
print(('Shreadsheet=%s Worksheet=%s' % (filename, sheet)))
|
||||
print('------------------------------------------------------------')
|
||||
crsr = conn.cursor()
|
||||
sql = "SELECT * from [%s]" % sheet
|
||||
crsr.execute(sql)
|
||||
for row in crsr.fetchmany(10):
|
||||
print((repr(row)))
|
||||
crsr.close()
|
||||
conn.close()
|
|
@ -1,32 +0,0 @@
|
|||
from __future__ import with_statement # needed only if running Python 2.5
|
||||
import adodbapi
|
||||
try:
|
||||
import adodbapi.is64bit as is64bit
|
||||
is64 = is64bit.Python()
|
||||
except ImportError:
|
||||
is64 = False # in case the user has an old version of adodbapi
|
||||
if is64:
|
||||
driver = "Microsoft.ACE.OLEDB.12.0"
|
||||
else:
|
||||
driver = "Microsoft.Jet.OLEDB.4.0"
|
||||
filename = 'xx.xls' # file will be created if it does not exist
|
||||
extended = 'Extended Properties="Excel 8.0;Readonly=False;"'
|
||||
|
||||
constr = "Provider=%s;Data Source=%s;%s" % (driver, filename, extended)
|
||||
|
||||
conn = adodbapi.connect(constr)
|
||||
with conn: # will auto commit if no errors
|
||||
with conn.cursor() as crsr:
|
||||
try: crsr.execute('drop table SheetOne')
|
||||
except: pass # just is case there is one already there
|
||||
|
||||
# create the sheet and the header row and set the types for the columns
|
||||
crsr.execute('create table SheetOne (Header1 text, Header2 text, Header3 text, Header4 text, Header5 text)')
|
||||
|
||||
sql = "INSERT INTO SheetOne (Header1, Header2 ,Header3, Header4, Header5) values (?,?,?,?,?)"
|
||||
|
||||
data = (1, 2, 3, 4, 5)
|
||||
crsr.execute(sql, data) # write the first row of data
|
||||
crsr.execute(sql, (6, 7, 8, 9, 10)) # another row of data
|
||||
conn.close()
|
||||
print(('Created spreadsheet=%s worksheet=%s' % (filename, 'SheetOne')))
|
|
@ -1,33 +0,0 @@
|
|||
"""is64bit.Python() --> boolean value of detected Python word size. is64bit.os() --> os build version"""
|
||||
import sys
|
||||
|
||||
def Python():
|
||||
if sys.platform == 'cli': #IronPython
|
||||
import System
|
||||
return System.IntPtr.Size == 8
|
||||
else:
|
||||
try:
|
||||
return sys.maxsize > 2147483647
|
||||
except AttributeError:
|
||||
return sys.maxint > 2147483647
|
||||
|
||||
def os():
|
||||
import platform
|
||||
pm = platform.machine()
|
||||
if pm != '..' and pm.endswith('64'): # recent Python (not Iron)
|
||||
return True
|
||||
else:
|
||||
import os
|
||||
if 'PROCESSOR_ARCHITEW6432' in os.environ:
|
||||
return True # 32 bit program running on 64 bit Windows
|
||||
try:
|
||||
return os.environ['PROCESSOR_ARCHITECTURE'].endswith('64') # 64 bit Windows 64 bit program
|
||||
except IndexError:
|
||||
pass # not Windows
|
||||
try:
|
||||
return '64' in platform.architecture()[0] # this often works in Linux
|
||||
except:
|
||||
return False # is an older version of Python, assume also an older os (best we can guess)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(("is64bit.Python() =", Python(), "is64bit.os() =", os()))
|
|
@ -1,506 +0,0 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
Project
|
||||
-------
|
||||
adodbapi
|
||||
|
||||
A Python DB-API 2.0 (PEP-249) module that makes it easy to use Microsoft ADO
|
||||
for connecting with databases and other data sources
|
||||
using either CPython or IronPython.
|
||||
|
||||
Home page: <http://sourceforge.net/projects/adodbapi>
|
||||
|
||||
Features:
|
||||
* 100% DB-API 2.0 (PEP-249) compliant (including most extensions and recommendations).
|
||||
* Includes pyunit testcases that describe how to use the module.
|
||||
* Fully implemented in Python. -- runs in Python 2.5+ Python 3.0+ and IronPython 2.6+
|
||||
* Licensed under the LGPL license, which means that it can be used freely even in commercial programs subject to certain restrictions.
|
||||
* Includes SERVER and REMOTE modules so that a Windows proxy can serve ADO databases to a Linux client using PyRO.
|
||||
* The user can choose between paramstyles: 'qmark' 'named' 'format' 'pyformat' 'dynamic'
|
||||
* Supports data retrieval by column name e.g.:
|
||||
for row in myCurser.execute("select name,age from students"):
|
||||
print("Student", row.name, "is", row.age, "years old.")
|
||||
* Supports user-definable system-to-Python data conversion functions (selected by ADO data type, or by column)
|
||||
|
||||
Prerequisites:
|
||||
* C Python 2.5 or higher
|
||||
and pywin32 (Mark Hammond's python for windows extensions.)
|
||||
or
|
||||
Iron Python 2.6 or higher. (works in IPy2.0 for all data types except BUFFER)
|
||||
|
||||
Installation:
|
||||
* (C-Python on Windows): Download pywin32 from http://sf.net/projects/pywin32 and install from .msi (adodbapi is included)
|
||||
* ((to use Windows as a server, also download and install Pyro4 (requires Python 2.6 or later))) https://pypi.python.org/pypi/Pyro4
|
||||
* (IronPython on Windows): Download adodbapi from http://sf.net/projects/adodbapi. Unpack the zip.
|
||||
Open a command window as an administrator. CD to the folder containing the unzipped files.
|
||||
Run "setup.py install" using the IronPython of your choice.
|
||||
* (Linux, as a client): download and install from PyPi: "pip install adodbapi Pyro4"
|
||||
|
||||
NOTE: ...........
|
||||
If you do not like the new default operation of returning Numeric columns as decimal.Decimal,
|
||||
you can select other options by the user defined conversion feature.
|
||||
Try:
|
||||
adodbapi.apibase.variantConversions[adodbapi.ado_consts.adNumeric] = adodbapi.apibase.cvtString
|
||||
or:
|
||||
adodbapi.apibase.variantConversions[adodbapi.ado_consts.adNumeric] = adodbapi.apibase.cvtFloat
|
||||
or:
|
||||
adodbapi.apibase.variantConversions[adodbapi.ado_consts.adNumeric] = write_your_own_convertion_function
|
||||
............
|
||||
whats new in version 2.6
|
||||
A cursor.prepare() method and support for prepared SQL statements.
|
||||
Lots of refactoring, especially of the Remote and Server modules (still to be treated as Beta code).
|
||||
The quick start document 'quick_reference.odt' will export as a nice-looking pdf.
|
||||
Added paramstyles 'pyformat' and 'dynamic'. If your 'paramstyle' is 'named' you _must_ pass a dictionary of
|
||||
parameters to your .execute() method. If your 'paramstyle' is 'format' 'pyformat' or 'dynamic', you _may_
|
||||
pass a dictionary of parameters -- provided your SQL operation string is formatted correctly.
|
||||
|
||||
whats new in version 2.5
|
||||
Remote module: (works on Linux!) allows a Windows computer to serve ADO databases via PyRO
|
||||
Server module: PyRO server for ADO. Run using a command like= C:>python -m adodbapi.server
|
||||
(server has simple connection string macros: is64bit, getuser, sql_provider, auto_security)
|
||||
Brief documentation included. See adodbapi/examples folder adodbapi.rtf
|
||||
New connection method conn.get_table_names() --> list of names of tables in database
|
||||
|
||||
Vastly refactored. Data conversion things have been moved to the new adodbapi.apibase module.
|
||||
Many former module-level attributes are now class attributes. (Should be more thread-safe)
|
||||
Connection objects are now context managers for transactions and will commit or rollback.
|
||||
Cursor objects are context managers and will automatically close themselves.
|
||||
Autocommit can be switched on and off.
|
||||
Keyword and positional arguments on the connect() method work as documented in PEP 249.
|
||||
Keyword arguments from the connect call can be formatted into the connection string.
|
||||
New keyword arguments defined, such as: autocommit, paramstyle, remote_proxy, remote_port.
|
||||
*** Breaking change: variantConversion lookups are simplified: the following will raise KeyError:
|
||||
oldconverter=adodbapi.variantConversions[adodbapi.adoStringTypes]
|
||||
Refactor as: oldconverter=adodbapi.variantConversions[adodbapi.adoStringTypes[0]]
|
||||
|
||||
(( More information like this in older_whatsnew.txt ))
|
||||
|
||||
License
|
||||
-------
|
||||
LGPL, see http://www.opensource.org/licenses/lgpl-license.php
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
Start with:
|
||||
|
||||
http://www.python.org/topics/database/DatabaseAPI-2.0.html
|
||||
read the examples in adodbapi/examples
|
||||
and look at the test cases in adodbapi/test directory.
|
||||
|
||||
Mailing lists
|
||||
-------------
|
||||
The adodbapi mailing lists have been deactivated. Submit comments to the
|
||||
pywin32 or IronPython mailing lists.
|
||||
-- the bug tracker on sourceforge.net/projects/adodbapi will be checked, (infrequently).
|
|
@ -1,14 +0,0 @@
|
|||
"""call using an open ADO connection --> list of table names"""
|
||||
from . import adodbapi
|
||||
|
||||
def names(connection_object):
|
||||
ado = connection_object.adoConn
|
||||
schema = ado.OpenSchema(20) # constant = adSchemaTables
|
||||
|
||||
tables = []
|
||||
while not schema.EOF:
|
||||
name = adodbapi.getIndexedValue(schema.Fields,'TABLE_NAME').Value
|
||||
tables.append(name)
|
||||
schema.MoveNext()
|
||||
del schema
|
||||
return tables
|
File diff suppressed because it is too large
Load diff
|
@ -1,161 +0,0 @@
|
|||
# Configure this to _YOUR_ environment in order to run the testcases.
|
||||
"testADOdbapiConfig.py v 2.6.0.A00"
|
||||
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# #
|
||||
# # TESTERS:
|
||||
# #
|
||||
# # You will need to make numerous modifications to this file
|
||||
# # to adapt it to your own testing environment.
|
||||
# #
|
||||
# # Skip down to the next "# #" line --
|
||||
# # -- the things you need to change are below it.
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
import platform
|
||||
import sys
|
||||
import random
|
||||
|
||||
import is64bit
|
||||
import setuptestframework
|
||||
if sys.version_info >= (3,0):
|
||||
import tryconnection3 as tryconnection
|
||||
else:
|
||||
import tryconnection2 as tryconnection
|
||||
|
||||
print((sys.version))
|
||||
node = platform.node()
|
||||
try: print(('node=%s: is64bit.os()= %s, is64bit.Python()= %s' % (node, is64bit.os(), is64bit.Python())))
|
||||
except: pass
|
||||
|
||||
try:
|
||||
onWindows = bool(sys.getwindowsversion()) # seems to work on all versions of Python
|
||||
except:
|
||||
onWindows = False
|
||||
|
||||
# create a random name for temporary table names
|
||||
_alphabet = "PYFGCRLAOEUIDHTNTQJKXBMWVZ1234567890" # yes, I do use a dvorak keyboard!
|
||||
tmp = ''.join([random.choice(_alphabet) for x in range(9)])
|
||||
mdb_name = 'xx_' + tmp + '.mdb'
|
||||
testfolder = setuptestframework.maketemp()
|
||||
|
||||
if '--package' in sys.argv:
|
||||
pth = setuptestframework.makeadopackage(testfolder)
|
||||
else:
|
||||
pth = setuptestframework.find_ado_path()
|
||||
if pth not in sys.path:
|
||||
sys.path.insert(1,pth)
|
||||
|
||||
# function to clean up the temporary folder -- calling program must run this function before exit.
|
||||
cleanup = setuptestframework.getcleanupfunction()
|
||||
|
||||
import adodbapi # will (hopefully) be imported using the "pth" discovered above
|
||||
|
||||
try:
|
||||
print((adodbapi.version)) # show version
|
||||
except:
|
||||
print('"adodbapi.version" not present or not working.')
|
||||
print(__doc__)
|
||||
|
||||
verbose = False
|
||||
for a in sys.argv:
|
||||
if a.startswith('--verbose'):
|
||||
arg = True
|
||||
try: arg = int(a.split("=")[1])
|
||||
except IndexError: pass
|
||||
adodbapi.adodbapi.verbose = arg
|
||||
verbose = arg
|
||||
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# # start your environment setup here v v v
|
||||
SQL_HOST_NODE = 'Vpad'
|
||||
doAllTests = '--all' in sys.argv
|
||||
doAccessTest = not ('--nojet' in sys.argv)
|
||||
doSqlServerTest = node == SQL_HOST_NODE or '--mssql' in sys.argv or doAllTests
|
||||
doMySqlTest = '--mysql' in sys.argv or doAllTests
|
||||
doPostgresTest = '--pg' in sys.argv or doAllTests
|
||||
iterateOverTimeTests = ('--time' in sys.argv or doAllTests) and onWindows
|
||||
|
||||
THE_PROXY_HOST = '25.44.77.176' if node != SQL_HOST_NODE or not onWindows else '::1' # -- change this
|
||||
|
||||
try: #If mx extensions are installed, use mxDateTime
|
||||
import mx.DateTime
|
||||
doMxDateTimeTest=True
|
||||
except:
|
||||
doMxDateTimeTest=False #Requires eGenixMXExtensions
|
||||
|
||||
doTimeTest = True # obsolete python time format
|
||||
|
||||
if doAccessTest:
|
||||
if onWindows and (node == SQL_HOST_NODE or not is64bit.Python()):
|
||||
c = {'mdb': setuptestframework.makemdb(testfolder, mdb_name)}
|
||||
else:
|
||||
c = {'macro_find_temp_test_path' : ['mdb', 'server_test.mdb'],
|
||||
'proxy_host' : THE_PROXY_HOST}
|
||||
|
||||
|
||||
# macro definition for keyword "driver" using macro "is64bit" -- see documentation
|
||||
c['macro_is64bit'] = ['driver', "Microsoft.ACE.OLEDB.12.0", "Microsoft.Jet.OLEDB.4.0"]
|
||||
connStrAccess = "Provider=%(driver)s;Data Source=%(mdb)s"
|
||||
print(' ...Testing ACCESS connection...')
|
||||
doAccessTest, connStrAccess, dbAccessconnect = tryconnection.try_connection(verbose, connStrAccess, 10, **c)
|
||||
|
||||
if doSqlServerTest:
|
||||
c = {'macro_getnode' : ['host', r"%s\SQLExpress"], # name of computer with SQL Server
|
||||
#'host':'25.44.77.176;' # Network Library=dbmssocn',
|
||||
'database': "adotest",
|
||||
'user' : 'adotestuser', # None implies Windows security
|
||||
'password' : "12345678",
|
||||
# macro definition for keyword "security" using macro "auto_security"
|
||||
'macro_auto_security' : 'security',
|
||||
'provider' : 'SQLNCLI11; MARS Connection=True'
|
||||
}
|
||||
connStr = "Provider=%(provider)s; Initial Catalog=%(database)s; Data Source=%(host)s; %(security)s;"
|
||||
|
||||
if node != SQL_HOST_NODE:
|
||||
if THE_PROXY_HOST:
|
||||
c["proxy_host"] = THE_PROXY_HOST # the SQL server runs a proxy for this test
|
||||
else:
|
||||
c["pyro_connection"] = "PYRONAME:ado.connection"
|
||||
print(' ...Testing MS-SQL login...')
|
||||
doSqlServerTest, connStrSQLServer, dbSqlServerconnect = tryconnection.try_connection(verbose, connStr, 30, **c)
|
||||
|
||||
if doMySqlTest:
|
||||
c = {'host' : "25.223.161.222",
|
||||
'database' : 'test',
|
||||
'user' : 'adotest',
|
||||
'password' : '12345678',
|
||||
'driver' : "MySQL ODBC 5.3 Unicode Driver"} # or _driver="MySQL ODBC 3.51 Driver
|
||||
|
||||
if not onWindows:
|
||||
if THE_PROXY_HOST:
|
||||
c["proxy_host"] = THE_PROXY_HOST
|
||||
else:
|
||||
c["pyro_connection"] = "PYRONAME:ado.connection"
|
||||
|
||||
c['macro_is64bit'] = ['provider', 'Provider=MSDASQL;']
|
||||
cs = '%(provider)sDriver={%(driver)s};Server=%(host)s;Port=3306;' + \
|
||||
'Database=%(database)s;user=%(user)s;password=%(password)s;Option=3;'
|
||||
print(' ...Testing MySql login...')
|
||||
doMySqlTest, connStrMySql, dbMySqlconnect = tryconnection.try_connection(verbose, cs, 5, **c)
|
||||
|
||||
if doPostgresTest:
|
||||
_computername = "25.223.161.222"
|
||||
_databasename='adotest'
|
||||
_username = 'adotestuser'
|
||||
_password = '12345678'
|
||||
kws = {'timeout' : 4}
|
||||
kws['macro_is64bit'] = ['prov_drv', 'Provider=MSDASQL;Driver={PostgreSQL Unicode(x64)}',
|
||||
'Driver=PostgreSQL Unicode']
|
||||
if not onWindows:
|
||||
if THE_PROXY_HOST:
|
||||
kws['proxy_host'] = THE_PROXY_HOST
|
||||
else:
|
||||
kws['pyro_connection'] = 'PYRONAME:ado.connection'
|
||||
# get driver from http://www.postgresql.org/ftp/odbc/versions/
|
||||
# test using positional and keyword arguments (bad example for real code)
|
||||
print(' ...Testing PostgreSQL login...')
|
||||
doPostgresTest, connStrPostgres, dbPostgresConnect = tryconnection.try_connection(verbose,
|
||||
'%(prov_drv)s;Server=%(host)s;Database=%(database)s;uid=%(user)s;pwd=%(password)s;',
|
||||
_username, _password, _computername, _databasename, **kws)
|
||||
|
||||
assert doAccessTest or doSqlServerTest or doMySqlTest or doPostgresTest, 'No database engine found for testing'
|
|
@ -1,899 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
''' Python DB API 2.0 driver compliance unit test suite.
|
||||
|
||||
This software is Public Domain and may be used without restrictions.
|
||||
|
||||
"Now we have booze and barflies entering the discussion, plus rumours of
|
||||
DBAs on drugs... and I won't tell you what flashes through my mind each
|
||||
time I read the subject line with 'Anal Compliance' in it. All around
|
||||
this is turning out to be a thoroughly unwholesome unit test."
|
||||
|
||||
-- Ian Bicking
|
||||
'''
|
||||
|
||||
__version__ = '$Revision: 1.14.3 $'[11:-2]
|
||||
__author__ = 'Stuart Bishop <stuart@stuartbishop.net>'
|
||||
|
||||
import unittest
|
||||
import time
|
||||
import sys
|
||||
|
||||
if sys.version[0] >= '3': #python 3.x
|
||||
_BaseException = Exception
|
||||
def _failUnless(self, expr, msg=None):
|
||||
self.assertTrue(expr, msg)
|
||||
else: #python 2.x
|
||||
from exceptions import Exception as _BaseException
|
||||
def _failUnless(self, expr, msg=None):
|
||||
self.failUnless(expr, msg) ## deprecated since Python 2.6
|
||||
|
||||
# set this to "True" to follow API 2.0 to the letter
|
||||
TEST_FOR_NON_IDEMPOTENT_CLOSE = True
|
||||
|
||||
# Revision 1.14 2013/05/20 11:02:05 kf7xm
|
||||
# Add a literal string to the format insertion test to catch trivial re-format algorithms
|
||||
|
||||
# Revision 1.13 2013/05/08 14:31:50 kf7xm
|
||||
# Quick switch to Turn off IDEMPOTENT_CLOSE test. Also: Silence teardown failure
|
||||
|
||||
# Revision 1.12 2009/02/06 03:35:11 kf7xm
|
||||
# Tested okay with Python 3.0, includes last minute patches from Mark H.
|
||||
#
|
||||
# Revision 1.1.1.1.2.1 2008/09/20 19:54:59 rupole
|
||||
# Include latest changes from main branch
|
||||
# Updates for py3k
|
||||
#
|
||||
# Revision 1.11 2005/01/02 02:41:01 zenzen
|
||||
# Update author email address
|
||||
#
|
||||
# Revision 1.10 2003/10/09 03:14:14 zenzen
|
||||
# Add test for DB API 2.0 optional extension, where database exceptions
|
||||
# are exposed as attributes on the Connection object.
|
||||
#
|
||||
# Revision 1.9 2003/08/13 01:16:36 zenzen
|
||||
# Minor tweak from Stefan Fleiter
|
||||
#
|
||||
# Revision 1.8 2003/04/10 00:13:25 zenzen
|
||||
# Changes, as per suggestions by M.-A. Lemburg
|
||||
# - Add a table prefix, to ensure namespace collisions can always be avoided
|
||||
#
|
||||
# Revision 1.7 2003/02/26 23:33:37 zenzen
|
||||
# Break out DDL into helper functions, as per request by David Rushby
|
||||
#
|
||||
# Revision 1.6 2003/02/21 03:04:33 zenzen
|
||||
# Stuff from Henrik Ekelund:
|
||||
# added test_None
|
||||
# added test_nextset & hooks
|
||||
#
|
||||
# Revision 1.5 2003/02/17 22:08:43 zenzen
|
||||
# Implement suggestions and code from Henrik Eklund - test that cursor.arraysize
|
||||
# defaults to 1 & generic cursor.callproc test added
|
||||
#
|
||||
# Revision 1.4 2003/02/15 00:16:33 zenzen
|
||||
# Changes, as per suggestions and bug reports by M.-A. Lemburg,
|
||||
# Matthew T. Kromer, Federico Di Gregorio and Daniel Dittmar
|
||||
# - Class renamed
|
||||
# - Now a subclass of TestCase, to avoid requiring the driver stub
|
||||
# to use multiple inheritance
|
||||
# - Reversed the polarity of buggy test in test_description
|
||||
# - Test exception heirarchy correctly
|
||||
# - self.populate is now self._populate(), so if a driver stub
|
||||
# overrides self.ddl1 this change propogates
|
||||
# - VARCHAR columns now have a width, which will hopefully make the
|
||||
# DDL even more portible (this will be reversed if it causes more problems)
|
||||
# - cursor.rowcount being checked after various execute and fetchXXX methods
|
||||
# - Check for fetchall and fetchmany returning empty lists after results
|
||||
# are exhausted (already checking for empty lists if select retrieved
|
||||
# nothing
|
||||
# - Fix bugs in test_setoutputsize_basic and test_setinputsizes
|
||||
#
|
||||
def str2bytes(sval):
|
||||
if sys.version_info < (3,0) and isinstance(sval, str):
|
||||
sval = sval.decode("latin1")
|
||||
return sval.encode("latin1") #python 3 make unicode into bytes
|
||||
|
||||
class DatabaseAPI20Test(unittest.TestCase):
|
||||
''' Test a database self.driver for DB API 2.0 compatibility.
|
||||
This implementation tests Gadfly, but the TestCase
|
||||
is structured so that other self.drivers can subclass this
|
||||
test case to ensure compiliance with the DB-API. It is
|
||||
expected that this TestCase may be expanded in the future
|
||||
if ambiguities or edge conditions are discovered.
|
||||
|
||||
The 'Optional Extensions' are not yet being tested.
|
||||
|
||||
self.drivers should subclass this test, overriding setUp, tearDown,
|
||||
self.driver, connect_args and connect_kw_args. Class specification
|
||||
should be as follows:
|
||||
|
||||
import dbapi20
|
||||
class mytest(dbapi20.DatabaseAPI20Test):
|
||||
[...]
|
||||
|
||||
Don't 'import DatabaseAPI20Test from dbapi20', or you will
|
||||
confuse the unit tester - just 'import dbapi20'.
|
||||
'''
|
||||
|
||||
# The self.driver module. This should be the module where the 'connect'
|
||||
# method is to be found
|
||||
driver = None
|
||||
connect_args = () # List of arguments to pass to connect
|
||||
connect_kw_args = {} # Keyword arguments for connect
|
||||
table_prefix = 'dbapi20test_' # If you need to specify a prefix for tables
|
||||
|
||||
ddl1 = 'create table %sbooze (name varchar(20))' % table_prefix
|
||||
ddl2 = 'create table %sbarflys (name varchar(20), drink varchar(30))' % table_prefix
|
||||
xddl1 = 'drop table %sbooze' % table_prefix
|
||||
xddl2 = 'drop table %sbarflys' % table_prefix
|
||||
|
||||
lowerfunc = 'lower' # Name of stored procedure to convert string->lowercase
|
||||
|
||||
# Some drivers may need to override these helpers, for example adding
|
||||
# a 'commit' after the execute.
|
||||
def executeDDL1(self,cursor):
|
||||
cursor.execute(self.ddl1)
|
||||
|
||||
def executeDDL2(self,cursor):
|
||||
cursor.execute(self.ddl2)
|
||||
|
||||
def setUp(self):
|
||||
''' self.drivers should override this method to perform required setup
|
||||
if any is necessary, such as creating the database.
|
||||
'''
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
''' self.drivers should override this method to perform required cleanup
|
||||
if any is necessary, such as deleting the test database.
|
||||
The default drops the tables that may be created.
|
||||
'''
|
||||
try:
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
for ddl in (self.xddl1,self.xddl2):
|
||||
try:
|
||||
cur.execute(ddl)
|
||||
con.commit()
|
||||
except self.driver.Error:
|
||||
# Assume table didn't exist. Other tests will check if
|
||||
# execute is busted.
|
||||
pass
|
||||
finally:
|
||||
con.close()
|
||||
except _BaseException:
|
||||
pass
|
||||
|
||||
def _connect(self):
|
||||
try:
|
||||
r = self.driver.connect(
|
||||
*self.connect_args,**self.connect_kw_args
|
||||
)
|
||||
except AttributeError:
|
||||
self.fail("No connect method found in self.driver module")
|
||||
return r
|
||||
|
||||
def test_connect(self):
|
||||
con = self._connect()
|
||||
con.close()
|
||||
|
||||
def test_apilevel(self):
|
||||
try:
|
||||
# Must exist
|
||||
apilevel = self.driver.apilevel
|
||||
# Must equal 2.0
|
||||
self.assertEqual(apilevel,'2.0')
|
||||
except AttributeError:
|
||||
self.fail("Driver doesn't define apilevel")
|
||||
|
||||
def test_threadsafety(self):
|
||||
try:
|
||||
# Must exist
|
||||
threadsafety = self.driver.threadsafety
|
||||
# Must be a valid value
|
||||
_failUnless(self, threadsafety in (0,1,2,3))
|
||||
except AttributeError:
|
||||
self.fail("Driver doesn't define threadsafety")
|
||||
|
||||
def test_paramstyle(self):
|
||||
try:
|
||||
# Must exist
|
||||
paramstyle = self.driver.paramstyle
|
||||
# Must be a valid value
|
||||
_failUnless(self, paramstyle in (
|
||||
'qmark','numeric','named','format','pyformat'
|
||||
))
|
||||
except AttributeError:
|
||||
self.fail("Driver doesn't define paramstyle")
|
||||
|
||||
def test_Exceptions(self):
|
||||
# Make sure required exceptions exist, and are in the
|
||||
# defined heirarchy.
|
||||
if sys.version[0] == '3': #under Python 3 StardardError no longer exists
|
||||
self.assertTrue(issubclass(self.driver.Warning,Exception))
|
||||
self.assertTrue(issubclass(self.driver.Error,Exception))
|
||||
else:
|
||||
self.failUnless(issubclass(self.driver.Warning,Exception))
|
||||
self.failUnless(issubclass(self.driver.Error,Exception))
|
||||
|
||||
_failUnless(self,
|
||||
issubclass(self.driver.InterfaceError,self.driver.Error)
|
||||
)
|
||||
_failUnless(self,
|
||||
issubclass(self.driver.DatabaseError,self.driver.Error)
|
||||
)
|
||||
_failUnless(self,
|
||||
issubclass(self.driver.OperationalError,self.driver.Error)
|
||||
)
|
||||
_failUnless(self,
|
||||
issubclass(self.driver.IntegrityError,self.driver.Error)
|
||||
)
|
||||
_failUnless(self,
|
||||
issubclass(self.driver.InternalError,self.driver.Error)
|
||||
)
|
||||
_failUnless(self,
|
||||
issubclass(self.driver.ProgrammingError,self.driver.Error)
|
||||
)
|
||||
_failUnless(self,
|
||||
issubclass(self.driver.NotSupportedError,self.driver.Error)
|
||||
)
|
||||
|
||||
def test_ExceptionsAsConnectionAttributes(self):
|
||||
# OPTIONAL EXTENSION
|
||||
# Test for the optional DB API 2.0 extension, where the exceptions
|
||||
# are exposed as attributes on the Connection object
|
||||
# I figure this optional extension will be implemented by any
|
||||
# driver author who is using this test suite, so it is enabled
|
||||
# by default.
|
||||
con = self._connect()
|
||||
drv = self.driver
|
||||
_failUnless(self,con.Warning is drv.Warning)
|
||||
_failUnless(self,con.Error is drv.Error)
|
||||
_failUnless(self,con.InterfaceError is drv.InterfaceError)
|
||||
_failUnless(self,con.DatabaseError is drv.DatabaseError)
|
||||
_failUnless(self,con.OperationalError is drv.OperationalError)
|
||||
_failUnless(self,con.IntegrityError is drv.IntegrityError)
|
||||
_failUnless(self,con.InternalError is drv.InternalError)
|
||||
_failUnless(self,con.ProgrammingError is drv.ProgrammingError)
|
||||
_failUnless(self,con.NotSupportedError is drv.NotSupportedError)
|
||||
|
||||
|
||||
def test_commit(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
# Commit must work, even if it doesn't do anything
|
||||
con.commit()
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_rollback(self):
|
||||
con = self._connect()
|
||||
# If rollback is defined, it should either work or throw
|
||||
# the documented exception
|
||||
if hasattr(con,'rollback'):
|
||||
try:
|
||||
con.rollback()
|
||||
except self.driver.NotSupportedError:
|
||||
pass
|
||||
|
||||
def test_cursor(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_cursor_isolation(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
# Make sure cursors created from the same connection have
|
||||
# the documented transaction isolation level
|
||||
cur1 = con.cursor()
|
||||
cur2 = con.cursor()
|
||||
self.executeDDL1(cur1)
|
||||
cur1.execute("insert into %sbooze values ('Victoria Bitter')" % (
|
||||
self.table_prefix
|
||||
))
|
||||
cur2.execute("select name from %sbooze" % self.table_prefix)
|
||||
booze = cur2.fetchall()
|
||||
self.assertEqual(len(booze),1)
|
||||
self.assertEqual(len(booze[0]),1)
|
||||
self.assertEqual(booze[0][0],'Victoria Bitter')
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_description(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
self.executeDDL1(cur)
|
||||
self.assertEqual(cur.description,None,
|
||||
'cursor.description should be none after executing a '
|
||||
'statement that can return no rows (such as DDL)'
|
||||
)
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
self.assertEqual(len(cur.description),1,
|
||||
'cursor.description describes too many columns'
|
||||
)
|
||||
self.assertEqual(len(cur.description[0]),7,
|
||||
'cursor.description[x] tuples must have 7 elements'
|
||||
)
|
||||
self.assertEqual(cur.description[0][0].lower(),'name',
|
||||
'cursor.description[x][0] must return column name'
|
||||
)
|
||||
self.assertEqual(cur.description[0][1],self.driver.STRING,
|
||||
'cursor.description[x][1] must return column type. Got %r'
|
||||
% cur.description[0][1]
|
||||
)
|
||||
|
||||
# Make sure self.description gets reset
|
||||
self.executeDDL2(cur)
|
||||
self.assertEqual(cur.description,None,
|
||||
'cursor.description not being set to None when executing '
|
||||
'no-result statements (eg. DDL)'
|
||||
)
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_rowcount(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
self.executeDDL1(cur)
|
||||
_failUnless(self,cur.rowcount in (-1,0), # Bug #543885
|
||||
'cursor.rowcount should be -1 or 0 after executing no-result '
|
||||
'statements'
|
||||
)
|
||||
cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
|
||||
self.table_prefix
|
||||
))
|
||||
_failUnless(self,cur.rowcount in (-1,1),
|
||||
'cursor.rowcount should == number or rows inserted, or '
|
||||
'set to -1 after executing an insert statement'
|
||||
)
|
||||
cur.execute("select name from %sbooze" % self.table_prefix)
|
||||
_failUnless(self,cur.rowcount in (-1,1),
|
||||
'cursor.rowcount should == number of rows returned, or '
|
||||
'set to -1 after executing a select statement'
|
||||
)
|
||||
self.executeDDL2(cur)
|
||||
self.assertEqual(cur.rowcount,-1,
|
||||
'cursor.rowcount not being reset to -1 after executing '
|
||||
'no-result statements'
|
||||
)
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
lower_func = 'lower'
|
||||
def test_callproc(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
if self.lower_func and hasattr(cur,'callproc'):
|
||||
r = cur.callproc(self.lower_func,('FOO',))
|
||||
self.assertEqual(len(r),1)
|
||||
self.assertEqual(r[0],'FOO')
|
||||
r = cur.fetchall()
|
||||
self.assertEqual(len(r),1,'callproc produced no result set')
|
||||
self.assertEqual(len(r[0]),1,
|
||||
'callproc produced invalid result set'
|
||||
)
|
||||
self.assertEqual(r[0][0],'foo',
|
||||
'callproc produced invalid results'
|
||||
)
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_close(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
# cursor.execute should raise an Error if called after connection
|
||||
# closed
|
||||
self.assertRaises(self.driver.Error,self.executeDDL1,cur)
|
||||
|
||||
# connection.commit should raise an Error if called after connection'
|
||||
# closed.'
|
||||
self.assertRaises(self.driver.Error,con.commit)
|
||||
|
||||
# connection.close should raise an Error if called more than once
|
||||
#!!! reasonable persons differ about the usefulness of this test and this feature !!!
|
||||
if TEST_FOR_NON_IDEMPOTENT_CLOSE:
|
||||
self.assertRaises(self.driver.Error,con.close)
|
||||
|
||||
def test_execute(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
self._paraminsert(cur)
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def _paraminsert(self,cur):
|
||||
self.executeDDL2(cur)
|
||||
cur.execute("insert into %sbarflys values ('Victoria Bitter', 'thi%%s :may ca%%(u)se? troub:1e')" % (
|
||||
self.table_prefix
|
||||
))
|
||||
_failUnless(self,cur.rowcount in (-1,1))
|
||||
|
||||
if self.driver.paramstyle == 'qmark':
|
||||
cur.execute(
|
||||
"insert into %sbarflys values (?, 'thi%%s :may ca%%(u)se? troub:1e')" % self.table_prefix,
|
||||
("Cooper's",)
|
||||
)
|
||||
elif self.driver.paramstyle == 'numeric':
|
||||
cur.execute(
|
||||
"insert into %sbarflys values (:1, 'thi%%s :may ca%%(u)se? troub:1e')" % self.table_prefix,
|
||||
("Cooper's",)
|
||||
)
|
||||
elif self.driver.paramstyle == 'named':
|
||||
cur.execute(
|
||||
"insert into %sbarflys values (:beer, 'thi%%s :may ca%%(u)se? troub:1e')" % self.table_prefix,
|
||||
{'beer':"Cooper's"}
|
||||
)
|
||||
elif self.driver.paramstyle == 'format':
|
||||
cur.execute(
|
||||
"insert into %sbarflys values (%%s, 'thi%%s :may ca%%(u)se? troub:1e')" % self.table_prefix,
|
||||
("Cooper's",)
|
||||
)
|
||||
elif self.driver.paramstyle == 'pyformat':
|
||||
cur.execute(
|
||||
"insert into %sbarflys values (%%(beer)s, 'thi%%s :may ca%%(u)se? troub:1e')" % self.table_prefix,
|
||||
{'beer':"Cooper's"}
|
||||
)
|
||||
else:
|
||||
self.fail('Invalid paramstyle')
|
||||
_failUnless(self,cur.rowcount in (-1,1))
|
||||
|
||||
cur.execute('select name, drink from %sbarflys' % self.table_prefix)
|
||||
res = cur.fetchall()
|
||||
self.assertEqual(len(res),2,'cursor.fetchall returned too few rows')
|
||||
beers = [res[0][0],res[1][0]]
|
||||
beers.sort()
|
||||
self.assertEqual(beers[0],"Cooper's",
|
||||
'cursor.fetchall retrieved incorrect data, or data inserted '
|
||||
'incorrectly'
|
||||
)
|
||||
self.assertEqual(beers[1],"Victoria Bitter",
|
||||
'cursor.fetchall retrieved incorrect data, or data inserted '
|
||||
'incorrectly'
|
||||
)
|
||||
trouble = "thi%s :may ca%(u)se? troub:1e"
|
||||
self.assertEqual(res[0][1], trouble,
|
||||
'cursor.fetchall retrieved incorrect data, or data inserted '
|
||||
'incorrectly. Got=%s, Expected=%s' % (repr(res[0][1]), repr(trouble)))
|
||||
self.assertEqual(res[1][1], trouble,
|
||||
'cursor.fetchall retrieved incorrect data, or data inserted '
|
||||
'incorrectly. Got=%s, Expected=%s' % (repr(res[1][1]), repr(trouble)
|
||||
))
|
||||
|
||||
def test_executemany(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
self.executeDDL1(cur)
|
||||
largs = [ ("Cooper's",) , ("Boag's",) ]
|
||||
margs = [ {'beer': "Cooper's"}, {'beer': "Boag's"} ]
|
||||
if self.driver.paramstyle == 'qmark':
|
||||
cur.executemany(
|
||||
'insert into %sbooze values (?)' % self.table_prefix,
|
||||
largs
|
||||
)
|
||||
elif self.driver.paramstyle == 'numeric':
|
||||
cur.executemany(
|
||||
'insert into %sbooze values (:1)' % self.table_prefix,
|
||||
largs
|
||||
)
|
||||
elif self.driver.paramstyle == 'named':
|
||||
cur.executemany(
|
||||
'insert into %sbooze values (:beer)' % self.table_prefix,
|
||||
margs
|
||||
)
|
||||
elif self.driver.paramstyle == 'format':
|
||||
cur.executemany(
|
||||
'insert into %sbooze values (%%s)' % self.table_prefix,
|
||||
largs
|
||||
)
|
||||
elif self.driver.paramstyle == 'pyformat':
|
||||
cur.executemany(
|
||||
'insert into %sbooze values (%%(beer)s)' % (
|
||||
self.table_prefix
|
||||
),
|
||||
margs
|
||||
)
|
||||
else:
|
||||
self.fail('Unknown paramstyle')
|
||||
_failUnless(self,cur.rowcount in (-1,2),
|
||||
'insert using cursor.executemany set cursor.rowcount to '
|
||||
'incorrect value %r' % cur.rowcount
|
||||
)
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
res = cur.fetchall()
|
||||
self.assertEqual(len(res),2,
|
||||
'cursor.fetchall retrieved incorrect number of rows'
|
||||
)
|
||||
beers = [res[0][0],res[1][0]]
|
||||
beers.sort()
|
||||
self.assertEqual(beers[0],"Boag's",'incorrect data "%s" retrieved' % beers[0])
|
||||
self.assertEqual(beers[1],"Cooper's",'incorrect data retrieved')
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_fetchone(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
|
||||
# cursor.fetchone should raise an Error if called before
|
||||
# executing a select-type query
|
||||
self.assertRaises(self.driver.Error,cur.fetchone)
|
||||
|
||||
# cursor.fetchone should raise an Error if called after
|
||||
# executing a query that cannnot return rows
|
||||
self.executeDDL1(cur)
|
||||
self.assertRaises(self.driver.Error,cur.fetchone)
|
||||
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
self.assertEqual(cur.fetchone(),None,
|
||||
'cursor.fetchone should return None if a query retrieves '
|
||||
'no rows'
|
||||
)
|
||||
_failUnless(self,cur.rowcount in (-1,0))
|
||||
|
||||
# cursor.fetchone should raise an Error if called after
|
||||
# executing a query that cannnot return rows
|
||||
cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
|
||||
self.table_prefix
|
||||
))
|
||||
self.assertRaises(self.driver.Error,cur.fetchone)
|
||||
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
r = cur.fetchone()
|
||||
self.assertEqual(len(r),1,
|
||||
'cursor.fetchone should have retrieved a single row'
|
||||
)
|
||||
self.assertEqual(r[0],'Victoria Bitter',
|
||||
'cursor.fetchone retrieved incorrect data'
|
||||
)
|
||||
self.assertEqual(cur.fetchone(),None,
|
||||
'cursor.fetchone should return None if no more rows available'
|
||||
)
|
||||
_failUnless(self,cur.rowcount in (-1,1))
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
samples = [
|
||||
'Carlton Cold',
|
||||
'Carlton Draft',
|
||||
'Mountain Goat',
|
||||
'Redback',
|
||||
'Victoria Bitter',
|
||||
'XXXX'
|
||||
]
|
||||
|
||||
def _populate(self):
|
||||
''' Return a list of sql commands to setup the DB for the fetch
|
||||
tests.
|
||||
'''
|
||||
populate = [
|
||||
"insert into %sbooze values ('%s')" % (self.table_prefix,s)
|
||||
for s in self.samples
|
||||
]
|
||||
return populate
|
||||
|
||||
def test_fetchmany(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
|
||||
# cursor.fetchmany should raise an Error if called without
|
||||
#issuing a query
|
||||
self.assertRaises(self.driver.Error,cur.fetchmany,4)
|
||||
|
||||
self.executeDDL1(cur)
|
||||
for sql in self._populate():
|
||||
cur.execute(sql)
|
||||
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
r = cur.fetchmany()
|
||||
self.assertEqual(len(r),1,
|
||||
'cursor.fetchmany retrieved incorrect number of rows, '
|
||||
'default of arraysize is one.'
|
||||
)
|
||||
cur.arraysize=10
|
||||
r = cur.fetchmany(3) # Should get 3 rows
|
||||
self.assertEqual(len(r),3,
|
||||
'cursor.fetchmany retrieved incorrect number of rows'
|
||||
)
|
||||
r = cur.fetchmany(4) # Should get 2 more
|
||||
self.assertEqual(len(r),2,
|
||||
'cursor.fetchmany retrieved incorrect number of rows'
|
||||
)
|
||||
r = cur.fetchmany(4) # Should be an empty sequence
|
||||
self.assertEqual(len(r),0,
|
||||
'cursor.fetchmany should return an empty sequence after '
|
||||
'results are exhausted'
|
||||
)
|
||||
_failUnless(self,cur.rowcount in (-1,6))
|
||||
|
||||
# Same as above, using cursor.arraysize
|
||||
cur.arraysize=4
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
r = cur.fetchmany() # Should get 4 rows
|
||||
self.assertEqual(len(r),4,
|
||||
'cursor.arraysize not being honoured by fetchmany'
|
||||
)
|
||||
r = cur.fetchmany() # Should get 2 more
|
||||
self.assertEqual(len(r),2)
|
||||
r = cur.fetchmany() # Should be an empty sequence
|
||||
self.assertEqual(len(r),0)
|
||||
_failUnless(self,cur.rowcount in (-1,6))
|
||||
|
||||
cur.arraysize=6
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
rows = cur.fetchmany() # Should get all rows
|
||||
_failUnless(self,cur.rowcount in (-1,6))
|
||||
self.assertEqual(len(rows),6)
|
||||
self.assertEqual(len(rows),6)
|
||||
rows = [r[0] for r in rows]
|
||||
rows.sort()
|
||||
|
||||
# Make sure we get the right data back out
|
||||
for i in range(0,6):
|
||||
self.assertEqual(rows[i],self.samples[i],
|
||||
'incorrect data retrieved by cursor.fetchmany'
|
||||
)
|
||||
|
||||
rows = cur.fetchmany() # Should return an empty list
|
||||
self.assertEqual(len(rows),0,
|
||||
'cursor.fetchmany should return an empty sequence if '
|
||||
'called after the whole result set has been fetched'
|
||||
)
|
||||
_failUnless(self,cur.rowcount in (-1,6))
|
||||
|
||||
self.executeDDL2(cur)
|
||||
cur.execute('select name from %sbarflys' % self.table_prefix)
|
||||
r = cur.fetchmany() # Should get empty sequence
|
||||
self.assertEqual(len(r),0,
|
||||
'cursor.fetchmany should return an empty sequence if '
|
||||
'query retrieved no rows'
|
||||
)
|
||||
_failUnless(self,cur.rowcount in (-1,0))
|
||||
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_fetchall(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
# cursor.fetchall should raise an Error if called
|
||||
# without executing a query that may return rows (such
|
||||
# as a select)
|
||||
self.assertRaises(self.driver.Error, cur.fetchall)
|
||||
|
||||
self.executeDDL1(cur)
|
||||
for sql in self._populate():
|
||||
cur.execute(sql)
|
||||
|
||||
# cursor.fetchall should raise an Error if called
|
||||
# after executing a a statement that cannot return rows
|
||||
self.assertRaises(self.driver.Error,cur.fetchall)
|
||||
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
rows = cur.fetchall()
|
||||
_failUnless(self,cur.rowcount in (-1,len(self.samples)))
|
||||
self.assertEqual(len(rows),len(self.samples),
|
||||
'cursor.fetchall did not retrieve all rows'
|
||||
)
|
||||
rows = [r[0] for r in rows]
|
||||
rows.sort()
|
||||
for i in range(0,len(self.samples)):
|
||||
self.assertEqual(rows[i],self.samples[i],
|
||||
'cursor.fetchall retrieved incorrect rows'
|
||||
)
|
||||
rows = cur.fetchall()
|
||||
self.assertEqual(
|
||||
len(rows),0,
|
||||
'cursor.fetchall should return an empty list if called '
|
||||
'after the whole result set has been fetched'
|
||||
)
|
||||
_failUnless(self,cur.rowcount in (-1,len(self.samples)))
|
||||
|
||||
self.executeDDL2(cur)
|
||||
cur.execute('select name from %sbarflys' % self.table_prefix)
|
||||
rows = cur.fetchall()
|
||||
_failUnless(self,cur.rowcount in (-1,0))
|
||||
self.assertEqual(len(rows),0,
|
||||
'cursor.fetchall should return an empty list if '
|
||||
'a select query returns no rows'
|
||||
)
|
||||
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_mixedfetch(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
self.executeDDL1(cur)
|
||||
for sql in self._populate():
|
||||
cur.execute(sql)
|
||||
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
rows1 = cur.fetchone()
|
||||
rows23 = cur.fetchmany(2)
|
||||
rows4 = cur.fetchone()
|
||||
rows56 = cur.fetchall()
|
||||
_failUnless(self,cur.rowcount in (-1,6))
|
||||
self.assertEqual(len(rows23),2,
|
||||
'fetchmany returned incorrect number of rows'
|
||||
)
|
||||
self.assertEqual(len(rows56),2,
|
||||
'fetchall returned incorrect number of rows'
|
||||
)
|
||||
|
||||
rows = [rows1[0]]
|
||||
rows.extend([rows23[0][0],rows23[1][0]])
|
||||
rows.append(rows4[0])
|
||||
rows.extend([rows56[0][0],rows56[1][0]])
|
||||
rows.sort()
|
||||
for i in range(0,len(self.samples)):
|
||||
self.assertEqual(rows[i],self.samples[i],
|
||||
'incorrect data retrieved or inserted'
|
||||
)
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def help_nextset_setUp(self,cur):
|
||||
''' Should create a procedure called deleteme
|
||||
that returns two result sets, first the
|
||||
number of rows in booze then "name from booze"
|
||||
'''
|
||||
raise NotImplementedError('Helper not implemented')
|
||||
#sql="""
|
||||
# create procedure deleteme as
|
||||
# begin
|
||||
# select count(*) from booze
|
||||
# select name from booze
|
||||
# end
|
||||
#"""
|
||||
#cur.execute(sql)
|
||||
|
||||
def help_nextset_tearDown(self,cur):
|
||||
'If cleaning up is needed after nextSetTest'
|
||||
raise NotImplementedError('Helper not implemented')
|
||||
#cur.execute("drop procedure deleteme")
|
||||
|
||||
def test_nextset(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
if not hasattr(cur,'nextset'):
|
||||
return
|
||||
|
||||
try:
|
||||
self.executeDDL1(cur)
|
||||
sql=self._populate()
|
||||
for sql in self._populate():
|
||||
cur.execute(sql)
|
||||
|
||||
self.help_nextset_setUp(cur)
|
||||
|
||||
cur.callproc('deleteme')
|
||||
numberofrows=cur.fetchone()
|
||||
assert numberofrows[0]== len(self.samples)
|
||||
assert cur.nextset()
|
||||
names=cur.fetchall()
|
||||
assert len(names) == len(self.samples)
|
||||
s=cur.nextset()
|
||||
assert s == None,'No more return sets, should return None'
|
||||
finally:
|
||||
self.help_nextset_tearDown(cur)
|
||||
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_nextset(self):
|
||||
raise NotImplementedError('Drivers need to override this test')
|
||||
|
||||
def test_arraysize(self):
|
||||
# Not much here - rest of the tests for this are in test_fetchmany
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
_failUnless(self,hasattr(cur,'arraysize'),
|
||||
'cursor.arraysize must be defined'
|
||||
)
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_setinputsizes(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
cur.setinputsizes( (25,) )
|
||||
self._paraminsert(cur) # Make sure cursor still works
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_setoutputsize_basic(self):
|
||||
# Basic test is to make sure setoutputsize doesn't blow up
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
cur.setoutputsize(1000)
|
||||
cur.setoutputsize(2000,0)
|
||||
self._paraminsert(cur) # Make sure the cursor still works
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_setoutputsize(self):
|
||||
# Real test for setoutputsize is driver dependant
|
||||
raise NotImplementedError('Driver needed to override this test')
|
||||
|
||||
def test_None(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
self.executeDDL1(cur)
|
||||
cur.execute('insert into %sbooze values (NULL)' % self.table_prefix)
|
||||
cur.execute('select name from %sbooze' % self.table_prefix)
|
||||
r = cur.fetchall()
|
||||
self.assertEqual(len(r),1)
|
||||
self.assertEqual(len(r[0]),1)
|
||||
self.assertEqual(r[0][0],None,'NULL value not returned as None')
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_Date(self):
|
||||
d1 = self.driver.Date(2002,12,25)
|
||||
d2 = self.driver.DateFromTicks(time.mktime((2002,12,25,0,0,0,0,0,0)))
|
||||
# Can we assume this? API doesn't specify, but it seems implied
|
||||
# self.assertEqual(str(d1),str(d2))
|
||||
|
||||
def test_Time(self):
|
||||
t1 = self.driver.Time(13,45,30)
|
||||
t2 = self.driver.TimeFromTicks(time.mktime((2001,1,1,13,45,30,0,0,0)))
|
||||
# Can we assume this? API doesn't specify, but it seems implied
|
||||
# self.assertEqual(str(t1),str(t2))
|
||||
|
||||
def test_Timestamp(self):
|
||||
t1 = self.driver.Timestamp(2002,12,25,13,45,30)
|
||||
t2 = self.driver.TimestampFromTicks(
|
||||
time.mktime((2002,12,25,13,45,30,0,0,0))
|
||||
)
|
||||
# Can we assume this? API doesn't specify, but it seems implied
|
||||
# self.assertEqual(str(t1),str(t2))
|
||||
|
||||
def test_Binary(self):
|
||||
b = self.driver.Binary(str2bytes('Something'))
|
||||
b = self.driver.Binary(str2bytes(''))
|
||||
|
||||
def test_STRING(self):
|
||||
_failUnless(self, hasattr(self.driver,'STRING'),
|
||||
'module.STRING must be defined'
|
||||
)
|
||||
|
||||
def test_BINARY(self):
|
||||
_failUnless(self, hasattr(self.driver,'BINARY'),
|
||||
'module.BINARY must be defined.'
|
||||
)
|
||||
|
||||
def test_NUMBER(self):
|
||||
_failUnless(self, hasattr(self.driver,'NUMBER'),
|
||||
'module.NUMBER must be defined.'
|
||||
)
|
||||
|
||||
def test_DATETIME(self):
|
||||
_failUnless(self, hasattr(self.driver,'DATETIME'),
|
||||
'module.DATETIME must be defined.'
|
||||
)
|
||||
|
||||
def test_ROWID(self):
|
||||
_failUnless(self, hasattr(self.driver,'ROWID'),
|
||||
'module.ROWID must be defined.'
|
||||
)
|
|
@ -1,33 +0,0 @@
|
|||
"""is64bit.Python() --> boolean value of detected Python word size. is64bit.os() --> os build version"""
|
||||
import sys
|
||||
|
||||
def Python():
|
||||
if sys.platform == 'cli': #IronPython
|
||||
import System
|
||||
return System.IntPtr.Size == 8
|
||||
else:
|
||||
try:
|
||||
return sys.maxsize > 2147483647
|
||||
except AttributeError:
|
||||
return sys.maxint > 2147483647
|
||||
|
||||
def os():
|
||||
import platform
|
||||
pm = platform.machine()
|
||||
if pm != '..' and pm.endswith('64'): # recent Python (not Iron)
|
||||
return True
|
||||
else:
|
||||
import os
|
||||
if 'PROCESSOR_ARCHITEW6432' in os.environ:
|
||||
return True # 32 bit program running on 64 bit Windows
|
||||
try:
|
||||
return os.environ['PROCESSOR_ARCHITECTURE'].endswith('64') # 64 bit Windows 64 bit program
|
||||
except IndexError:
|
||||
pass # not Windows
|
||||
try:
|
||||
return '64' in platform.architecture()[0] # this often works in Linux
|
||||
except:
|
||||
return False # is an older version of Python, assume also an older os (best we can guess)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(("is64bit.Python() =", Python(), "is64bit.os() =", os()))
|
|
@ -1,113 +0,0 @@
|
|||
#!/usr/bin/python2
|
||||
# Configure this in order to run the testcases.
|
||||
"setuptestframework.py v 2.5.0.c9"
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
try:
|
||||
OSErrors = (WindowsError, OSError)
|
||||
except NameError: # not running on Windows
|
||||
OSErrors = OSError
|
||||
|
||||
def maketemp():
|
||||
temphome = tempfile.gettempdir()
|
||||
tempdir = os.path.join(temphome, 'adodbapi_test')
|
||||
## try: ## if running simultanous test, don't erase the other thread's work
|
||||
## shutil.rmtree(tempdir) # kill off an old copy
|
||||
## except: pass
|
||||
try: os.mkdir(tempdir)
|
||||
except: pass
|
||||
return tempdir
|
||||
|
||||
def _cleanup_function(testfolder, mdb_name):
|
||||
try: os.unlink(os.path.join(testfolder, mdb_name))
|
||||
except: pass # mdb database not present
|
||||
try: shutil.rmtree(os.path.join(testfolder, 'adodbapi'))
|
||||
except: pass # test package not present
|
||||
|
||||
def getcleanupfunction():
|
||||
return _cleanup_function
|
||||
|
||||
def find_ado_path():
|
||||
adoName = os.path.normpath(os.getcwd() + '/../../adodbapi.py')
|
||||
adoPackage = os.path.dirname(adoName)
|
||||
return adoPackage
|
||||
|
||||
# make a new package directory for the test copy of ado
|
||||
def makeadopackage(testfolder):
|
||||
adoName = os.path.normpath(os.getcwd() + '/../adodbapi.py')
|
||||
adoPath = os.path.dirname(adoName)
|
||||
if os.path.exists(adoName):
|
||||
newpackage = os.path.join(testfolder,'adodbapi')
|
||||
try:
|
||||
os.mkdir(newpackage)
|
||||
except OSErrors:
|
||||
print('*Note: temporary adodbapi package already exists: may be two versions running?')
|
||||
for f in os.listdir(adoPath):
|
||||
if f.endswith('.py'):
|
||||
shutil.copy(os.path.join(adoPath, f), newpackage)
|
||||
if sys.version_info >= (3,0): # only when running Py3.n
|
||||
save = sys.stdout
|
||||
sys.stdout = None
|
||||
from lib2to3.main import main # use 2to3 to make test package
|
||||
main("lib2to3.fixes",args=['-n','-w', newpackage])
|
||||
sys.stdout = save
|
||||
return testfolder
|
||||
else:
|
||||
raise EnvironmentError('Connot find source of adodbapi to test.')
|
||||
|
||||
def makemdb(testfolder, mdb_name):
|
||||
# following setup code borrowed from pywin32 odbc test suite
|
||||
# kindly contributed by Frank Millman.
|
||||
import os
|
||||
|
||||
_accessdatasource = os.path.join(testfolder, mdb_name)
|
||||
if not os.path.isfile(_accessdatasource):
|
||||
try:
|
||||
from win32com.client.gencache import EnsureDispatch
|
||||
from win32com.client import constants
|
||||
win32 = True
|
||||
except ImportError: #perhaps we are running IronPython
|
||||
win32 = False #iron Python
|
||||
try:
|
||||
from System import Activator, Type
|
||||
except:
|
||||
pass
|
||||
|
||||
# Create a brand-new database - what is the story with these?
|
||||
dbe = None
|
||||
for suffix in (".36", ".35", ".30"):
|
||||
try:
|
||||
if win32:
|
||||
dbe = EnsureDispatch("DAO.DBEngine" + suffix)
|
||||
else:
|
||||
type= Type.GetTypeFromProgID("DAO.DBEngine" + suffix)
|
||||
dbe = Activator.CreateInstance(type)
|
||||
break
|
||||
except:
|
||||
pass
|
||||
if dbe:
|
||||
print((' ...Creating ACCESS db at '+_accessdatasource))
|
||||
if win32:
|
||||
workspace = dbe.Workspaces(0)
|
||||
newdb = workspace.CreateDatabase(_accessdatasource,
|
||||
constants.dbLangGeneral,
|
||||
constants.dbEncrypt)
|
||||
else:
|
||||
newdb = dbe.CreateDatabase(_accessdatasource,';LANGID=0x0409;CP=1252;COUNTRY=0')
|
||||
newdb.Close()
|
||||
else:
|
||||
print((' ...copying test ACCESS db to '+_accessdatasource))
|
||||
mdbName = os.path.normpath(os.getcwd() + '/../examples/test.mdb')
|
||||
import shutil
|
||||
shutil.copy(mdbName, _accessdatasource)
|
||||
|
||||
return _accessdatasource
|
||||
|
||||
if __name__ == "__main__":
|
||||
print('Setting up a Jet database for server to use for remote testing...')
|
||||
temp = maketemp()
|
||||
makemdb(temp, 'server_test.mdb')
|
|
@ -1,181 +0,0 @@
|
|||
print("This module depends on the dbapi20 compliance tests created by Stuart Bishop")
|
||||
print("(see db-sig mailing list history for info)")
|
||||
import platform
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
import dbapi20
|
||||
import setuptestframework
|
||||
|
||||
testfolder = setuptestframework.maketemp()
|
||||
if '--package' in sys.argv:
|
||||
pth = setuptestframework.makeadopackage(testfolder)
|
||||
sys.argv.remove('--package')
|
||||
else:
|
||||
pth = setuptestframework.find_ado_path()
|
||||
if pth not in sys.path:
|
||||
sys.path.insert(1,pth)
|
||||
# function to clean up the temporary folder -- calling program must run this function before exit.
|
||||
cleanup = setuptestframework.getcleanupfunction()
|
||||
|
||||
import adodbapi
|
||||
import adodbapi.is64bit as is64bit
|
||||
db = adodbapi
|
||||
|
||||
if '--verbose' in sys.argv:
|
||||
db.adodbapi.verbose = 3
|
||||
|
||||
print((adodbapi.version))
|
||||
print(("Tested with dbapi20 %s" % dbapi20.__version__))
|
||||
|
||||
try:
|
||||
onWindows = bool(sys.getwindowsversion()) # seems to work on all versions of Python
|
||||
except:
|
||||
onWindows = False
|
||||
|
||||
node = platform.node()
|
||||
|
||||
conn_kws = {}
|
||||
host = None # if None, will use macro to fill in node name
|
||||
instance = r'%s\SQLExpress'
|
||||
conn_kws['name'] = 'adotest'
|
||||
|
||||
if host is None:
|
||||
conn_kws['macro_getnode'] = ['host', instance]
|
||||
else:
|
||||
conn_kws['host'] = host
|
||||
|
||||
conn_kws['provider'] = 'Provider=SQLNCLI11;DataTypeCompatibility=80;MARS Connection=True;'
|
||||
connStr = "%(provider)s; Integrated Security=SSPI; Initial Catalog=%(name)s;Data Source=%(host)s"
|
||||
|
||||
if onWindows and node != "z-PC":
|
||||
pass # default should make a local SQL Server connection
|
||||
elif node == "xxx": # try Postgres database
|
||||
_computername = "25.223.161.222"
|
||||
_databasename='adotest'
|
||||
_username = 'adotestuser'
|
||||
_password = '12345678'
|
||||
_driver="PostgreSQL Unicode"
|
||||
_provider = ''
|
||||
connStr = '%sDriver={%s};Server=%s;Database=%s;uid=%s;pwd=%s;' % \
|
||||
(_provider,_driver,_computername,_databasename,_username,_password)
|
||||
elif node == "yyy": # ACCESS data base is known to fail some tests.
|
||||
if is64bit.Python():
|
||||
driver = "Microsoft.ACE.OLEDB.12.0"
|
||||
else:
|
||||
driver = "Microsoft.Jet.OLEDB.4.0"
|
||||
testmdb = setuptestframework.makemdb(testfolder)
|
||||
connStr = r"Provider=%s;Data Source=%s" % (driver, testmdb)
|
||||
else: # try a remote connection to an SQL server
|
||||
conn_kws['proxy_host'] = '25.44.77.176'
|
||||
import adodbapi.remote
|
||||
db = adodbapi.remote
|
||||
|
||||
print(('Using Connection String like=%s' % connStr))
|
||||
print(('Keywords=%s' % repr(conn_kws)))
|
||||
|
||||
class test_adodbapi(dbapi20.DatabaseAPI20Test):
|
||||
driver = db
|
||||
connect_args = (connStr,)
|
||||
connect_kw_args = conn_kws
|
||||
|
||||
def __init__(self,arg):
|
||||
dbapi20.DatabaseAPI20Test.__init__(self,arg)
|
||||
|
||||
def testMethodName(self):
|
||||
return self.id().split('.')[-1]
|
||||
|
||||
def setUp(self):
|
||||
# Call superclass setUp In case this does something in the
|
||||
# future
|
||||
dbapi20.DatabaseAPI20Test.setUp(self)
|
||||
if self.testMethodName()=='test_callproc':
|
||||
con = self._connect()
|
||||
engine = con.dbms_name
|
||||
## print('Using database Engine=%s' % engine) ##
|
||||
if engine != 'MS Jet':
|
||||
sql="""
|
||||
create procedure templower
|
||||
@theData varchar(50)
|
||||
as
|
||||
select lower(@theData)
|
||||
"""
|
||||
else: # Jet
|
||||
sql="""
|
||||
create procedure templower
|
||||
(theData varchar(50))
|
||||
as
|
||||
select lower(theData);
|
||||
"""
|
||||
cur = con.cursor()
|
||||
try:
|
||||
cur.execute(sql)
|
||||
con.commit()
|
||||
except:
|
||||
pass
|
||||
cur.close()
|
||||
con.close()
|
||||
self.lower_func='templower'
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
if self.testMethodName()=='test_callproc':
|
||||
con = self._connect()
|
||||
cur = con.cursor()
|
||||
try:
|
||||
cur.execute("drop procedure templower")
|
||||
except:
|
||||
pass
|
||||
con.commit()
|
||||
dbapi20.DatabaseAPI20Test.tearDown(self)
|
||||
|
||||
|
||||
def help_nextset_setUp(self,cur):
|
||||
'Should create a procedure called deleteme '
|
||||
'that returns two result sets, first the number of rows in booze then "name from booze"'
|
||||
sql="""
|
||||
create procedure deleteme as
|
||||
begin
|
||||
select count(*) from %sbooze
|
||||
select name from %sbooze
|
||||
end
|
||||
""" %(self.table_prefix,self.table_prefix)
|
||||
cur.execute(sql)
|
||||
|
||||
def help_nextset_tearDown(self,cur):
|
||||
'If cleaning up is needed after nextSetTest'
|
||||
try:
|
||||
cur.execute("drop procedure deleteme")
|
||||
except:
|
||||
pass
|
||||
|
||||
def test_nextset(self):
|
||||
con = self._connect()
|
||||
try:
|
||||
cur = con.cursor()
|
||||
|
||||
stmts=[self.ddl1] + self._populate()
|
||||
for sql in stmts:
|
||||
cur.execute(sql)
|
||||
|
||||
self.help_nextset_setUp(cur)
|
||||
|
||||
cur.callproc('deleteme')
|
||||
numberofrows=cur.fetchone()
|
||||
assert numberofrows[0]== 6
|
||||
assert cur.nextset()
|
||||
names=cur.fetchall()
|
||||
assert len(names) == len(self.samples)
|
||||
s=cur.nextset()
|
||||
assert s == None,'No more return sets, should return None'
|
||||
finally:
|
||||
try:
|
||||
self.help_nextset_tearDown(cur)
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
def test_setoutputsize(self): pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
cleanup(testfolder, None)
|
|
@ -1,46 +0,0 @@
|
|||
# This module may be retired as soon as Python 2.5 support is dropped.
|
||||
#
|
||||
# It exists only to allow trapping exceptions using the "except [exception list], e" format
|
||||
# which is a syntax error in Python 3
|
||||
|
||||
def try_connection(verbose, *args, **kwargs):
|
||||
import adodbapi
|
||||
|
||||
if "proxy_host" in kwargs or 'pyro_connection' in kwargs or 'proxy_host' in args:
|
||||
import adodbapi.remote
|
||||
import Pyro4
|
||||
pyroError = Pyro4.errors.PyroError
|
||||
dbconnect = adodbapi.remote.connect
|
||||
remote = True
|
||||
else:
|
||||
dbconnect = adodbapi.connect
|
||||
pyroError = NotImplementedError # (will not occur)
|
||||
remote = False
|
||||
try:
|
||||
s = dbconnect(*args, **kwargs) # connect to server
|
||||
if verbose:
|
||||
print('Connected to:', s.connection_string)
|
||||
print('which has tables:', s.get_table_names())
|
||||
s.close() # thanks, it worked, goodbye
|
||||
except (adodbapi.DatabaseError, pyroError) as inst:
|
||||
print(inst.args[0]) # should be the error message
|
||||
print('***Failed getting connection using=', repr(args), repr(kwargs))
|
||||
if remote:
|
||||
print('** Is your Python2 ado.connection server running?')
|
||||
print('* Have you run "setuptestframework.py" to create server_test.mdb?')
|
||||
return False, (args, kwargs), None
|
||||
|
||||
if remote:
|
||||
print(" (remote)", end=' ')
|
||||
print(" (successful)")
|
||||
|
||||
return True, (args, kwargs, remote), dbconnect
|
||||
|
||||
def try_operation_with_expected_exception(expected_exceptions, some_function, args, kwargs):
|
||||
try:
|
||||
some_function(*args, **kwargs)
|
||||
except expected_exceptions as e:
|
||||
return True, e
|
||||
except:
|
||||
raise # an exception other than the expected occurred
|
||||
return False, 'The expected exception did not occur'
|
|
@ -1,48 +0,0 @@
|
|||
from __future__ import print_function
|
||||
# This module may be retired as soon as Python 2.5 support is dropped.
|
||||
#
|
||||
# It exists only to allow trapping exceptions using the "except [exception list] as e" format
|
||||
# which is a syntax error in Python 2.5
|
||||
|
||||
def try_connection(verbose, *args, **kwargs):
|
||||
import adodbapi
|
||||
|
||||
if "proxy_host" in kwargs or "pyro_connection" in kwargs or "proxy_host" in args:
|
||||
import adodbapi.remote
|
||||
import Pyro4
|
||||
pyroError = Pyro4.errors.PyroError
|
||||
dbconnect = adodbapi.remote.connect
|
||||
remote = True
|
||||
else:
|
||||
dbconnect = adodbapi.connect
|
||||
pyroError = NotImplementedError # (will not occur)
|
||||
remote = False
|
||||
try:
|
||||
s = dbconnect(*args, **kwargs) # connect to server
|
||||
if verbose:
|
||||
print('Connected to:', s.connection_string)
|
||||
print('which has tables:', s.get_table_names())
|
||||
s.close() # thanks, it worked, goodbye
|
||||
except adodbapi.DatabaseError as inst:
|
||||
print(inst.args[0]) # should be the error message
|
||||
print('***Failed getting connection using=',repr(args),repr(kwargs))
|
||||
if remote:
|
||||
print('** Are you running a *Python3* ado.connection server? **')
|
||||
print('* Have you run "setuptestframework.py" to create server_test.mdb?')
|
||||
return False, (args, kwargs), None
|
||||
|
||||
if remote:
|
||||
print(" (remote)",end="")
|
||||
print(" (successful)")
|
||||
|
||||
return True, (args, kwargs, remote), dbconnect
|
||||
|
||||
|
||||
def try_operation_with_expected_exception(expected_exception_list, some_function, *args, **kwargs):
|
||||
try:
|
||||
some_function(*args, **kwargs)
|
||||
except expected_exception_list as e:
|
||||
return True, e
|
||||
except:
|
||||
raise # an exception other than the expected occurred
|
||||
return False, 'The expected exception did not occur'
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,620 +0,0 @@
|
|||
# postinstall script for pywin32
|
||||
#
|
||||
# copies PyWinTypesxx.dll and PythonCOMxx.dll into the system directory,
|
||||
# and creates a pth file
|
||||
import os, sys, glob, shutil, time
|
||||
import winreg as winreg
|
||||
|
||||
# Send output somewhere so it can be found if necessary...
|
||||
import tempfile
|
||||
tee_f = open(os.path.join(tempfile.gettempdir(), 'pywin32_postinstall.log'), "w")
|
||||
class Tee:
|
||||
def __init__(self, file):
|
||||
self.f = file
|
||||
def write(self, what):
|
||||
if self.f is not None:
|
||||
try:
|
||||
self.f.write(what.replace("\n", "\r\n"))
|
||||
except IOError:
|
||||
pass
|
||||
tee_f.write(what)
|
||||
def flush(self):
|
||||
if self.f is not None:
|
||||
try:
|
||||
self.f.flush()
|
||||
except IOError:
|
||||
pass
|
||||
tee_f.flush()
|
||||
|
||||
# For some unknown reason, when running under bdist_wininst we will start up
|
||||
# with sys.stdout as None but stderr is hooked up. This work-around allows
|
||||
# bdist_wininst to see the output we write and display it at the end of
|
||||
# the install.
|
||||
if sys.stdout is None:
|
||||
sys.stdout = sys.stderr
|
||||
|
||||
sys.stderr = Tee(sys.stderr)
|
||||
sys.stdout = Tee(sys.stdout)
|
||||
|
||||
com_modules = [
|
||||
# module_name, class_names
|
||||
("win32com.servers.interp", "Interpreter"),
|
||||
("win32com.servers.dictionary", "DictionaryPolicy"),
|
||||
("win32com.axscript.client.pyscript","PyScript"),
|
||||
]
|
||||
|
||||
# Is this a 'silent' install - ie, avoid all dialogs.
|
||||
# Different than 'verbose'
|
||||
silent = 0
|
||||
|
||||
# Verbosity of output messages.
|
||||
verbose = 1
|
||||
|
||||
ver_string = "%d.%d" % (sys.version_info[0], sys.version_info[1])
|
||||
root_key_name = "Software\\Python\\PythonCore\\" + ver_string
|
||||
|
||||
try:
|
||||
# When this script is run from inside the bdist_wininst installer,
|
||||
# file_created() and directory_created() are additional builtin
|
||||
# functions which write lines to Python23\pywin32-install.log. This is
|
||||
# a list of actions for the uninstaller, the format is inspired by what
|
||||
# the Wise installer also creates.
|
||||
file_created
|
||||
is_bdist_wininst = True
|
||||
except NameError:
|
||||
is_bdist_wininst = False # we know what it is not - but not what it is :)
|
||||
def file_created(file):
|
||||
pass
|
||||
def directory_created(directory):
|
||||
pass
|
||||
def get_root_hkey():
|
||||
try:
|
||||
winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
|
||||
root_key_name, 0, winreg.KEY_CREATE_SUB_KEY)
|
||||
return winreg.HKEY_LOCAL_MACHINE
|
||||
except OSError as details:
|
||||
# Either not exist, or no permissions to create subkey means
|
||||
# must be HKCU
|
||||
return winreg.HKEY_CURRENT_USER
|
||||
|
||||
try:
|
||||
create_shortcut
|
||||
except NameError:
|
||||
# Create a function with the same signature as create_shortcut provided
|
||||
# by bdist_wininst
|
||||
def create_shortcut(path, description, filename,
|
||||
arguments="", workdir="", iconpath="", iconindex=0):
|
||||
import pythoncom
|
||||
from win32com.shell import shell, shellcon
|
||||
|
||||
ilink = pythoncom.CoCreateInstance(shell.CLSID_ShellLink, None,
|
||||
pythoncom.CLSCTX_INPROC_SERVER,
|
||||
shell.IID_IShellLink)
|
||||
ilink.SetPath(path)
|
||||
ilink.SetDescription(description)
|
||||
if arguments:
|
||||
ilink.SetArguments(arguments)
|
||||
if workdir:
|
||||
ilink.SetWorkingDirectory(workdir)
|
||||
if iconpath or iconindex:
|
||||
ilink.SetIconLocation(iconpath, iconindex)
|
||||
# now save it.
|
||||
ipf = ilink.QueryInterface(pythoncom.IID_IPersistFile)
|
||||
ipf.Save(filename, 0)
|
||||
|
||||
# Support the same list of "path names" as bdist_wininst.
|
||||
def get_special_folder_path(path_name):
|
||||
import pythoncom
|
||||
from win32com.shell import shell, shellcon
|
||||
|
||||
for maybe in """
|
||||
CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA
|
||||
CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY
|
||||
CSIDL_DESKTOPDIRECTORY CSIDL_COMMON_STARTUP CSIDL_STARTUP
|
||||
CSIDL_COMMON_PROGRAMS CSIDL_PROGRAMS CSIDL_PROGRAM_FILES_COMMON
|
||||
CSIDL_PROGRAM_FILES CSIDL_FONTS""".split():
|
||||
if maybe == path_name:
|
||||
csidl = getattr(shellcon, maybe)
|
||||
return shell.SHGetSpecialFolderPath(0, csidl, False)
|
||||
raise ValueError("%s is an unknown path ID" % (path_name,))
|
||||
|
||||
def CopyTo(desc, src, dest):
|
||||
import win32api, win32con
|
||||
while 1:
|
||||
try:
|
||||
win32api.CopyFile(src, dest, 0)
|
||||
return
|
||||
except win32api.error as details:
|
||||
if details.winerror==5: # access denied - user not admin.
|
||||
raise
|
||||
if silent:
|
||||
# Running silent mode - just re-raise the error.
|
||||
raise
|
||||
tb = None
|
||||
full_desc = "Error %s\n\n" \
|
||||
"If you have any Python applications running, " \
|
||||
"please close them now\nand select 'Retry'\n\n%s" \
|
||||
% (desc, details.strerror)
|
||||
rc = win32api.MessageBox(0,
|
||||
full_desc,
|
||||
"Installation Error",
|
||||
win32con.MB_ABORTRETRYIGNORE)
|
||||
if rc == win32con.IDABORT:
|
||||
raise
|
||||
elif rc == win32con.IDIGNORE:
|
||||
return
|
||||
# else retry - around we go again.
|
||||
|
||||
# We need to import win32api to determine the Windows system directory,
|
||||
# so we can copy our system files there - but importing win32api will
|
||||
# load the pywintypes.dll already in the system directory preventing us
|
||||
# from updating them!
|
||||
# So, we pull the same trick pywintypes.py does, but it loads from
|
||||
# our pywintypes_system32 directory.
|
||||
def LoadSystemModule(lib_dir, modname):
|
||||
# See if this is a debug build.
|
||||
import imp
|
||||
for suffix_item in imp.get_suffixes():
|
||||
if suffix_item[0]=='_d.pyd':
|
||||
suffix = '_d'
|
||||
break
|
||||
else:
|
||||
suffix = ""
|
||||
filename = "%s%d%d%s.dll" % \
|
||||
(modname, sys.version_info[0], sys.version_info[1], suffix)
|
||||
filename = os.path.join(lib_dir, "pywin32_system32", filename)
|
||||
mod = imp.load_dynamic(modname, filename)
|
||||
|
||||
|
||||
def SetPyKeyVal(key_name, value_name, value):
|
||||
root_hkey = get_root_hkey()
|
||||
root_key = winreg.OpenKey(root_hkey, root_key_name)
|
||||
try:
|
||||
my_key = winreg.CreateKey(root_key, key_name)
|
||||
try:
|
||||
winreg.SetValueEx(my_key, value_name, 0, winreg.REG_SZ, value)
|
||||
finally:
|
||||
my_key.Close()
|
||||
finally:
|
||||
root_key.Close()
|
||||
if verbose:
|
||||
print("-> %s\\%s[%s]=%r" % (root_key_name, key_name, value_name, value))
|
||||
|
||||
def RegisterCOMObjects(register = 1):
|
||||
import win32com.server.register
|
||||
if register:
|
||||
func = win32com.server.register.RegisterClasses
|
||||
else:
|
||||
func = win32com.server.register.UnregisterClasses
|
||||
flags = {}
|
||||
if not verbose:
|
||||
flags['quiet']=1
|
||||
for module, klass_name in com_modules:
|
||||
__import__(module)
|
||||
mod = sys.modules[module]
|
||||
flags["finalize_register"] = getattr(mod, "DllRegisterServer", None)
|
||||
flags["finalize_unregister"] = getattr(mod, "DllUnregisterServer", None)
|
||||
klass = getattr(mod, klass_name)
|
||||
func(klass, **flags)
|
||||
|
||||
def RegisterPythonwin(register=True):
|
||||
""" Add (or remove) Pythonwin to context menu for python scripts.
|
||||
??? Should probably also add Edit command for pys files also.
|
||||
Also need to remove these keys on uninstall, but there's no function
|
||||
like file_created to add registry entries to uninstall log ???
|
||||
"""
|
||||
import os, distutils.sysconfig
|
||||
|
||||
lib_dir = distutils.sysconfig.get_python_lib(plat_specific=1)
|
||||
classes_root=get_root_hkey()
|
||||
## Installer executable doesn't seem to pass anything to postinstall script indicating if it's a debug build,
|
||||
pythonwin_exe = os.path.join(lib_dir, "Pythonwin", "Pythonwin.exe")
|
||||
pythonwin_edit_command=pythonwin_exe + ' /edit "%1"'
|
||||
|
||||
keys_vals = [
|
||||
('Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Pythonwin.exe', '', pythonwin_exe),
|
||||
('Software\\Classes\\Python.File\\shell\\Edit with Pythonwin', 'command', pythonwin_edit_command),
|
||||
('Software\\Classes\\Python.NoConFile\\shell\\Edit with Pythonwin', 'command', pythonwin_edit_command),
|
||||
]
|
||||
|
||||
try:
|
||||
if register:
|
||||
for key, sub_key, val in keys_vals:
|
||||
## Since winreg only uses the character Api functions, this can fail if Python
|
||||
## is installed to a path containing non-ascii characters
|
||||
hkey = winreg.CreateKey(classes_root, key)
|
||||
if sub_key:
|
||||
hkey = winreg.CreateKey(hkey, sub_key)
|
||||
winreg.SetValueEx(hkey, None, 0, winreg.REG_SZ, val)
|
||||
hkey.Close()
|
||||
else:
|
||||
for key, sub_key, val in keys_vals:
|
||||
try:
|
||||
winreg.DeleteKey(classes_root, key)
|
||||
except OSError as why:
|
||||
winerror = getattr(why, 'winerror', why.errno)
|
||||
if winerror != 2: # file not found
|
||||
raise
|
||||
finally:
|
||||
# tell windows about the change
|
||||
from win32com.shell import shell, shellcon
|
||||
shell.SHChangeNotify(shellcon.SHCNE_ASSOCCHANGED, shellcon.SHCNF_IDLIST, None, None)
|
||||
|
||||
def get_shortcuts_folder():
|
||||
if get_root_hkey()==winreg.HKEY_LOCAL_MACHINE:
|
||||
try:
|
||||
fldr = get_special_folder_path("CSIDL_COMMON_PROGRAMS")
|
||||
except OSError:
|
||||
# No CSIDL_COMMON_PROGRAMS on this platform
|
||||
fldr = get_special_folder_path("CSIDL_PROGRAMS")
|
||||
else:
|
||||
# non-admin install - always goes in this user's start menu.
|
||||
fldr = get_special_folder_path("CSIDL_PROGRAMS")
|
||||
|
||||
try:
|
||||
install_group = winreg.QueryValue(get_root_hkey(),
|
||||
root_key_name + "\\InstallPath\\InstallGroup")
|
||||
except OSError:
|
||||
vi = sys.version_info
|
||||
install_group = "Python %d.%d" % (vi[0], vi[1])
|
||||
return os.path.join(fldr, install_group)
|
||||
|
||||
# Get the system directory, which may be the Wow64 directory if we are a 32bit
|
||||
# python on a 64bit OS.
|
||||
def get_system_dir():
|
||||
import win32api # we assume this exists.
|
||||
try:
|
||||
import pythoncom
|
||||
import win32process
|
||||
from win32com.shell import shell, shellcon
|
||||
try:
|
||||
if win32process.IsWow64Process():
|
||||
return shell.SHGetSpecialFolderPath(0,shellcon.CSIDL_SYSTEMX86)
|
||||
return shell.SHGetSpecialFolderPath(0,shellcon.CSIDL_SYSTEM)
|
||||
except (pythoncom.com_error, win32process.error):
|
||||
return win32api.GetSystemDirectory()
|
||||
except ImportError:
|
||||
return win32api.GetSystemDirectory()
|
||||
|
||||
def fixup_dbi():
|
||||
# We used to have a dbi.pyd with our .pyd files, but now have a .py file.
|
||||
# If the user didn't uninstall, they will find the .pyd which will cause
|
||||
# problems - so handle that.
|
||||
import win32api, win32con
|
||||
pyd_name = os.path.join(os.path.dirname(win32api.__file__), "dbi.pyd")
|
||||
pyd_d_name = os.path.join(os.path.dirname(win32api.__file__), "dbi_d.pyd")
|
||||
py_name = os.path.join(os.path.dirname(win32con.__file__), "dbi.py")
|
||||
for this_pyd in (pyd_name, pyd_d_name):
|
||||
this_dest = this_pyd + ".old"
|
||||
if os.path.isfile(this_pyd) and os.path.isfile(py_name):
|
||||
try:
|
||||
if os.path.isfile(this_dest):
|
||||
print("Old dbi '%s' already exists - deleting '%s'" % (this_dest, this_pyd))
|
||||
os.remove(this_pyd)
|
||||
else:
|
||||
os.rename(this_pyd, this_dest)
|
||||
print("renamed '%s'->'%s.old'" % (this_pyd, this_pyd))
|
||||
file_created(this_pyd+".old")
|
||||
except os.error as exc:
|
||||
print("FAILED to rename '%s': %s" % (this_pyd, exc))
|
||||
|
||||
def install():
|
||||
import distutils.sysconfig
|
||||
import traceback
|
||||
# The .pth file is now installed as a regular file.
|
||||
# Create the .pth file in the site-packages dir, and use only relative paths
|
||||
lib_dir = distutils.sysconfig.get_python_lib(plat_specific=1)
|
||||
# We used to write a .pth directly to sys.prefix - clobber it.
|
||||
if os.path.isfile(os.path.join(sys.prefix, "pywin32.pth")):
|
||||
os.unlink(os.path.join(sys.prefix, "pywin32.pth"))
|
||||
# The .pth may be new and therefore not loaded in this session.
|
||||
# Setup the paths just in case.
|
||||
for name in "win32 win32\\lib Pythonwin".split():
|
||||
sys.path.append(os.path.join(lib_dir, name))
|
||||
# It is possible people with old versions installed with still have
|
||||
# pywintypes and pythoncom registered. We no longer need this, and stale
|
||||
# entries hurt us.
|
||||
for name in "pythoncom pywintypes".split():
|
||||
keyname = "Software\\Python\\PythonCore\\" + sys.winver + "\\Modules\\" + name
|
||||
for root in winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER:
|
||||
try:
|
||||
winreg.DeleteKey(root, keyname + "\\Debug")
|
||||
except WindowsError:
|
||||
pass
|
||||
try:
|
||||
winreg.DeleteKey(root, keyname)
|
||||
except WindowsError:
|
||||
pass
|
||||
LoadSystemModule(lib_dir, "pywintypes")
|
||||
LoadSystemModule(lib_dir, "pythoncom")
|
||||
import win32api
|
||||
# and now we can get the system directory:
|
||||
files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*"))
|
||||
if not files:
|
||||
raise RuntimeError("No system files to copy!!")
|
||||
# Try the system32 directory first - if that fails due to "access denied",
|
||||
# it implies a non-admin user, and we use sys.prefix
|
||||
for dest_dir in [get_system_dir(), sys.prefix]:
|
||||
# and copy some files over there
|
||||
worked = 0
|
||||
try:
|
||||
for fname in files:
|
||||
base = os.path.basename(fname)
|
||||
dst = os.path.join(dest_dir, base)
|
||||
CopyTo("installing %s" % base, fname, dst)
|
||||
if verbose:
|
||||
print("Copied %s to %s" % (base, dst))
|
||||
# Register the files with the uninstaller
|
||||
file_created(dst)
|
||||
worked = 1
|
||||
# If this isn't sys.prefix (ie, System32), then nuke
|
||||
# any versions that may exist in sys.prefix - having
|
||||
# duplicates causes major headaches.
|
||||
if dest_dir != sys.prefix:
|
||||
bad_fname = os.path.join(sys.prefix, base)
|
||||
if os.path.exists(bad_fname):
|
||||
# let exceptions go here - delete must succeed
|
||||
os.unlink(bad_fname)
|
||||
if worked:
|
||||
break
|
||||
except win32api.error as details:
|
||||
if details.winerror==5:
|
||||
# access denied - user not admin - try sys.prefix dir,
|
||||
# but first check that a version doesn't already exist
|
||||
# in that place - otherwise that one will still get used!
|
||||
if os.path.exists(dst):
|
||||
msg = "The file '%s' exists, but can not be replaced " \
|
||||
"due to insufficient permissions. You must " \
|
||||
"reinstall this software as an Administrator" \
|
||||
% dst
|
||||
print(msg)
|
||||
raise RuntimeError(msg)
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"You don't have enough permissions to install the system files")
|
||||
|
||||
# Pythonwin 'compiles' config files - record them for uninstall.
|
||||
pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin")
|
||||
for fname in glob.glob(os.path.join(pywin_dir, "*.cfg")):
|
||||
file_created(fname[:-1] + "c") # .cfg->.cfc
|
||||
|
||||
# Register our demo COM objects.
|
||||
try:
|
||||
try:
|
||||
RegisterCOMObjects()
|
||||
except win32api.error as details:
|
||||
if details.winerror!=5: # ERROR_ACCESS_DENIED
|
||||
raise
|
||||
print("You do not have the permissions to install COM objects.")
|
||||
print("The sample COM objects were not registered.")
|
||||
except:
|
||||
print("FAILED to register the Python COM objects")
|
||||
traceback.print_exc()
|
||||
|
||||
# There may be no main Python key in HKCU if, eg, an admin installed
|
||||
# python itself.
|
||||
winreg.CreateKey(get_root_hkey(), root_key_name)
|
||||
|
||||
# Register the .chm help file.
|
||||
chm_file = os.path.join(lib_dir, "PyWin32.chm")
|
||||
if os.path.isfile(chm_file):
|
||||
# This isn't recursive, so if 'Help' doesn't exist, we croak
|
||||
SetPyKeyVal("Help", None, None)
|
||||
SetPyKeyVal("Help\\Pythonwin Reference", None, chm_file)
|
||||
else:
|
||||
print("NOTE: PyWin32.chm can not be located, so has not " \
|
||||
"been registered")
|
||||
|
||||
# misc other fixups.
|
||||
fixup_dbi()
|
||||
|
||||
# Register Pythonwin in context menu
|
||||
try:
|
||||
RegisterPythonwin()
|
||||
except:
|
||||
print('Failed to register pythonwin as editor')
|
||||
traceback.print_exc()
|
||||
else:
|
||||
if verbose:
|
||||
print('Pythonwin has been registered in context menu')
|
||||
|
||||
# Create the win32com\gen_py directory.
|
||||
make_dir = os.path.join(lib_dir, "win32com", "gen_py")
|
||||
if not os.path.isdir(make_dir):
|
||||
if verbose:
|
||||
print("Creating directory", make_dir)
|
||||
directory_created(make_dir)
|
||||
os.mkdir(make_dir)
|
||||
|
||||
try:
|
||||
# create shortcuts
|
||||
# CSIDL_COMMON_PROGRAMS only available works on NT/2000/XP, and
|
||||
# will fail there if the user has no admin rights.
|
||||
fldr = get_shortcuts_folder()
|
||||
# If the group doesn't exist, then we don't make shortcuts - its
|
||||
# possible that this isn't a "normal" install.
|
||||
if os.path.isdir(fldr):
|
||||
dst = os.path.join(fldr, "PythonWin.lnk")
|
||||
create_shortcut(os.path.join(lib_dir, "Pythonwin\\Pythonwin.exe"),
|
||||
"The Pythonwin IDE", dst, "", sys.prefix)
|
||||
file_created(dst)
|
||||
if verbose:
|
||||
print("Shortcut for Pythonwin created")
|
||||
# And the docs.
|
||||
dst = os.path.join(fldr, "Python for Windows Documentation.lnk")
|
||||
doc = "Documentation for the PyWin32 extensions"
|
||||
create_shortcut(chm_file, doc, dst)
|
||||
file_created(dst)
|
||||
if verbose:
|
||||
print("Shortcut to documentation created")
|
||||
else:
|
||||
if verbose:
|
||||
print("Can't install shortcuts - %r is not a folder" % (fldr,))
|
||||
except Exception as details:
|
||||
print(details)
|
||||
|
||||
# importing win32com.client ensures the gen_py dir created - not strictly
|
||||
# necessary to do now, but this makes the installation "complete"
|
||||
try:
|
||||
import win32com.client
|
||||
except ImportError:
|
||||
# Don't let this error sound fatal
|
||||
pass
|
||||
print("The pywin32 extensions were successfully installed.")
|
||||
|
||||
def uninstall():
|
||||
import distutils.sysconfig
|
||||
lib_dir = distutils.sysconfig.get_python_lib(plat_specific=1)
|
||||
# First ensure our system modules are loaded from pywin32_system, so
|
||||
# we can remove the ones we copied...
|
||||
LoadSystemModule(lib_dir, "pywintypes")
|
||||
LoadSystemModule(lib_dir, "pythoncom")
|
||||
|
||||
try:
|
||||
RegisterCOMObjects(False)
|
||||
except Exception as why:
|
||||
print("Failed to unregister COM objects:", why)
|
||||
|
||||
try:
|
||||
RegisterPythonwin(False)
|
||||
except Exception as why:
|
||||
print("Failed to unregister Pythonwin:", why)
|
||||
else:
|
||||
if verbose:
|
||||
print('Unregistered Pythonwin')
|
||||
|
||||
try:
|
||||
# remove gen_py directory.
|
||||
gen_dir = os.path.join(lib_dir, "win32com", "gen_py")
|
||||
if os.path.isdir(gen_dir):
|
||||
shutil.rmtree(gen_dir)
|
||||
if verbose:
|
||||
print("Removed directory", gen_dir)
|
||||
|
||||
# Remove pythonwin compiled "config" files.
|
||||
pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin")
|
||||
for fname in glob.glob(os.path.join(pywin_dir, "*.cfc")):
|
||||
os.remove(fname)
|
||||
|
||||
# The dbi.pyd.old files we may have created.
|
||||
try:
|
||||
os.remove(os.path.join(lib_dir, "win32", "dbi.pyd.old"))
|
||||
except os.error:
|
||||
pass
|
||||
try:
|
||||
os.remove(os.path.join(lib_dir, "win32", "dbi_d.pyd.old"))
|
||||
except os.error:
|
||||
pass
|
||||
|
||||
except Exception as why:
|
||||
print("Failed to remove misc files:", why)
|
||||
|
||||
try:
|
||||
fldr = get_shortcuts_folder()
|
||||
for link in ("PythonWin.lnk", "Python for Windows Documentation.lnk"):
|
||||
fqlink = os.path.join(fldr, link)
|
||||
if os.path.isfile(fqlink):
|
||||
os.remove(fqlink)
|
||||
if verbose:
|
||||
print("Removed", link)
|
||||
except Exception as why:
|
||||
print("Failed to remove shortcuts:", why)
|
||||
# Now remove the system32 files.
|
||||
files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*"))
|
||||
# Try the system32 directory first - if that fails due to "access denied",
|
||||
# it implies a non-admin user, and we use sys.prefix
|
||||
try:
|
||||
for dest_dir in [get_system_dir(), sys.prefix]:
|
||||
# and copy some files over there
|
||||
worked = 0
|
||||
for fname in files:
|
||||
base = os.path.basename(fname)
|
||||
dst = os.path.join(dest_dir, base)
|
||||
if os.path.isfile(dst):
|
||||
try:
|
||||
os.remove(dst)
|
||||
worked = 1
|
||||
if verbose:
|
||||
print("Removed file %s" % (dst))
|
||||
except Exception:
|
||||
print("FAILED to remove", dst)
|
||||
if worked:
|
||||
break
|
||||
except Exception as why:
|
||||
print("FAILED to remove system files:", why)
|
||||
|
||||
def usage():
|
||||
msg = \
|
||||
"""%s: A post-install script for the pywin32 extensions.
|
||||
|
||||
Typical usage:
|
||||
|
||||
> python pywin32_postinstall.py -install
|
||||
|
||||
If you installed pywin32 via a .exe installer, this should be run
|
||||
automatically after installation, but if it fails you can run it again.
|
||||
|
||||
If you installed pywin32 via PIP, you almost certainly need to run this to
|
||||
setup the environment correctly.
|
||||
|
||||
Execute with script with a '-install' parameter, to ensure the environment
|
||||
is setup correctly.
|
||||
|
||||
Options:
|
||||
-install : Configure the Python environment correctly for pywin32.
|
||||
-remove : Try and remove everything that was installed or copied.
|
||||
-wait pid : Wait for the specified process to terminate before starting.
|
||||
-silent : Don't display the "Abort/Retry/Ignore" dialog for files in use.
|
||||
-quiet : Don't display progress messages.
|
||||
"""
|
||||
print(msg.strip() % os.path.basename(sys.argv[0]))
|
||||
|
||||
# NOTE: If this script is run from inside the bdist_wininst created
|
||||
# binary installer or uninstaller, the command line args are either
|
||||
# '-install' or '-remove'.
|
||||
|
||||
# Important: From inside the binary installer this script MUST NOT
|
||||
# call sys.exit() or raise SystemExit, otherwise not only this script
|
||||
# but also the installer will terminate! (Is there a way to prevent
|
||||
# this from the bdist_wininst C code?)
|
||||
|
||||
if __name__=='__main__':
|
||||
if len(sys.argv)==1:
|
||||
usage()
|
||||
sys.exit(1)
|
||||
|
||||
arg_index = 1
|
||||
while arg_index < len(sys.argv):
|
||||
arg = sys.argv[arg_index]
|
||||
# Hack for installing while we are in use. Just a simple wait so the
|
||||
# parent process can terminate.
|
||||
if arg == "-wait":
|
||||
arg_index += 1
|
||||
pid = int(sys.argv[arg_index])
|
||||
try:
|
||||
os.waitpid(pid, 0)
|
||||
except AttributeError:
|
||||
# Python 2.2 - no waitpid - just sleep.
|
||||
time.sleep(3)
|
||||
except os.error:
|
||||
# child already dead
|
||||
pass
|
||||
elif arg == "-install":
|
||||
install()
|
||||
elif arg == "-silent":
|
||||
silent = 1
|
||||
elif arg == "-quiet":
|
||||
verbose = 0
|
||||
elif arg == "-remove":
|
||||
# bdist_msi calls us before uninstall, so we can undo what we
|
||||
# previously did. Sadly, bdist_wininst calls us *after*, so
|
||||
# we can't do much at all.
|
||||
if not is_bdist_wininst:
|
||||
uninstall()
|
||||
else:
|
||||
print("Unknown option:", arg)
|
||||
usage()
|
||||
sys.exit(0)
|
||||
arg_index += 1
|
|
@ -1,88 +0,0 @@
|
|||
"""A test runner for pywin32"""
|
||||
import sys
|
||||
import os
|
||||
import distutils.sysconfig
|
||||
import win32api
|
||||
|
||||
# locate the dirs based on where this script is - it may be either in the
|
||||
# source tree, or in an installed Python 'Scripts' tree.
|
||||
this_dir = os.path.dirname(__file__)
|
||||
site_packages = distutils.sysconfig.get_python_lib(plat_specific=1)
|
||||
|
||||
if hasattr(os, 'popen3'):
|
||||
def run_test(script, cmdline_rest=""):
|
||||
dirname, scriptname = os.path.split(script)
|
||||
# some tests prefer to be run from their directory.
|
||||
cwd = os.getcwd()
|
||||
os.chdir(dirname)
|
||||
try:
|
||||
executable = win32api.GetShortPathName(sys.executable)
|
||||
cmd = '%s "%s" %s' % (sys.executable, scriptname, cmdline_rest)
|
||||
print(script)
|
||||
stdin, stdout, stderr = os.popen3(cmd)
|
||||
stdin.close()
|
||||
while 1:
|
||||
char = stderr.read(1)
|
||||
if not char:
|
||||
break
|
||||
sys.stdout.write(char)
|
||||
for line in stdout.readlines():
|
||||
print(line)
|
||||
stdout.close()
|
||||
result = stderr.close()
|
||||
if result is not None:
|
||||
print("****** %s failed: %s" % (script, result))
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
else:
|
||||
# a subprocess version - but we prefer the popen one if we can as we can
|
||||
# see test results as they are run (whereas this one waits until the test
|
||||
# is finished...)
|
||||
import subprocess
|
||||
def run_test(script, cmdline_rest=""):
|
||||
dirname, scriptname = os.path.split(script)
|
||||
# some tests prefer to be run from their directory.
|
||||
cmd = [sys.executable, "-u", scriptname] + cmdline_rest.split()
|
||||
print(script)
|
||||
popen = subprocess.Popen(cmd, shell=True, cwd=dirname,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
data = popen.communicate()[0]
|
||||
sys.stdout.buffer.write(data)
|
||||
if popen.returncode:
|
||||
print("****** %s failed: %s" % (script, popen.returncode))
|
||||
|
||||
|
||||
def find_and_run(possible_locations, script, cmdline_rest=""):
|
||||
for maybe in possible_locations:
|
||||
if os.path.isfile(os.path.join(maybe, script)):
|
||||
run_test(os.path.abspath(os.path.join(maybe, script)), cmdline_rest)
|
||||
break
|
||||
else:
|
||||
raise RuntimeError("Failed to locate the test script '%s' in one of %s"
|
||||
% (script, possible_locations))
|
||||
|
||||
if __name__=='__main__':
|
||||
# win32
|
||||
maybes = [os.path.join(this_dir, "win32", "test"),
|
||||
os.path.join(site_packages, "win32", "test"),
|
||||
]
|
||||
find_and_run(maybes, 'testall.py')
|
||||
|
||||
# win32com
|
||||
maybes = [os.path.join(this_dir, "com", "win32com", "test"),
|
||||
os.path.join(site_packages, "win32com", "test"),
|
||||
]
|
||||
find_and_run(maybes, 'testall.py', "2")
|
||||
|
||||
# adodbapi
|
||||
maybes = [os.path.join(this_dir, "adodbapi", "tests"),
|
||||
os.path.join(site_packages, "adodbapi", "tests"),
|
||||
]
|
||||
find_and_run(maybes, 'adodbapitest.py')
|
||||
# This script has a hard-coded sql server name in it, (and markh typically
|
||||
# doesn't have a different server to test on) so don't bother trying to
|
||||
# run it...
|
||||
# find_and_run(maybes, 'test_adodbapi_dbapi20.py')
|
||||
|
||||
if sys.version_info > (3,):
|
||||
print("** The tests have some issues on py3k - not all failures are a problem...")
|
Binary file not shown.
Binary file not shown.
|
@ -1,7 +0,0 @@
|
|||
A Python ISAPI extension. Contributed by Phillip Frantz, and is
|
||||
Copyright 2002-2003 by Blackdog Software Pty Ltd.
|
||||
|
||||
See the 'samples' directory, and particularly samples\README.txt
|
||||
|
||||
You can find documentation in the PyWin32.chm file that comes with pywin32 -
|
||||
you can open this from Pythonwin->Help, or from the start menu.
|
|
@ -1,33 +0,0 @@
|
|||
# The Python ISAPI package.
|
||||
|
||||
# Exceptions thrown by the DLL framework.
|
||||
class ISAPIError(Exception):
|
||||
def __init__(self, errno, strerror = None, funcname = None):
|
||||
# named attributes match IOError etc.
|
||||
self.errno = errno
|
||||
self.strerror = strerror
|
||||
self.funcname = funcname
|
||||
Exception.__init__(self, errno, strerror, funcname)
|
||||
def __str__(self):
|
||||
if self.strerror is None:
|
||||
try:
|
||||
import win32api
|
||||
self.strerror = win32api.FormatMessage(self.errno).strip()
|
||||
except:
|
||||
self.strerror = "no error message is available"
|
||||
# str() looks like a win32api error.
|
||||
return str( (self.errno, self.strerror, self.funcname) )
|
||||
|
||||
class FilterError(ISAPIError):
|
||||
pass
|
||||
|
||||
class ExtensionError(ISAPIError):
|
||||
pass
|
||||
|
||||
# A little development aid - a filter or extension callback function can
|
||||
# raise one of these exceptions, and the handler module will be reloaded.
|
||||
# This means you can change your code without restarting IIS.
|
||||
# After a reload, your filter/extension will have the GetFilterVersion/
|
||||
# GetExtensionVersion function called, but with None as the first arg.
|
||||
class InternalReloadException(Exception):
|
||||
pass
|
|
@ -1,92 +0,0 @@
|
|||
<!-- NOTE: This HTML is displayed inside the CHM file - hence some hrefs
|
||||
will only work in that environment
|
||||
-->
|
||||
<HTML>
|
||||
<BODY>
|
||||
<TITLE>Introduction to Python ISAPI support</TITLE>
|
||||
|
||||
<h2>Introduction to Python ISAPI support</h2>
|
||||
|
||||
<h3>See also</h3>
|
||||
<ul>
|
||||
<li><a href="/isapi_modules.html">The isapi related modules</a>
|
||||
</li>
|
||||
<li><a href="/isapi_objects.html">The isapi related objects</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p><i>Note: if you are viewing this documentation directly from disk,
|
||||
most links in this document will fail - you can also find this document in the
|
||||
CHM file that comes with pywin32, where the links will work</i>
|
||||
|
||||
<h3>Introduction</h3>
|
||||
This documents Python support for hosting ISAPI exensions and filters inside
|
||||
Microsoft Internet Information Server (IIS). It assumes a basic understanding
|
||||
of the ISAPI filter and extension mechanism.
|
||||
<p>
|
||||
In summary, to implement a filter or extension, you provide a Python module
|
||||
which defines a Filter and/or Extension class. Once your class has been
|
||||
loaded, IIS/ISAPI will, via an extension DLL, call methods on your class.
|
||||
<p>
|
||||
A filter and a class instance need only provide 3 methods - for filters they
|
||||
are called <code>GetFilterVersion</code>, <code>HttpFilterProc</code> and
|
||||
<code>TerminateFilter</code>. For extensions they
|
||||
are named <code>GetExtensionVersion</code>, <code>HttpExtensionProc</code> and
|
||||
<code>TerminateExtension</code>. If you are familiar with writing ISAPI
|
||||
extensions in C/C++, these names and their purpose will be familiar.
|
||||
<p>
|
||||
Most of the work is done in the <code>HttpFilterProc</code> and
|
||||
<code>HttpExtensionProc</code> methods. These both take a single
|
||||
parameter - an <a href="/HTTP_FILTER_CONTEXT.html">HTTP_FILTER_CONTEXT</a> and
|
||||
<a href="/EXTENSION_CONTROL_BLOCK.html">EXTENSION_CONTROL_BLOCK</a>
|
||||
object respectively.
|
||||
<p>
|
||||
In addition to these components, there is an 'isapi' package, containing
|
||||
support facilities (base-classes, exceptions, etc) which can be leveraged
|
||||
by the extension.
|
||||
|
||||
<h4>Base classes</h4>
|
||||
There are a number of base classes provided to make writing extensions a little
|
||||
simpler. Of particular note is <code>isapi.threaded_extension.ThreadPoolExtension</code>.
|
||||
This implements a thread-pool and informs IIS that the request is progressing
|
||||
in the background. Your sub-class need only provide a <code>Dispatch</code>
|
||||
method, which is called on one of the worker threads rather than the thread
|
||||
that the request came in on.
|
||||
<p>
|
||||
There is base-class for a filter in <code>isapi.simple</code>, but there is no
|
||||
equivilent threaded filter - filters work under a different model, where
|
||||
background processing is not possible.
|
||||
<h4>Samples</h4>
|
||||
Please see the <code>isapi/samples</code> directory for some sample filters
|
||||
and extensions.
|
||||
|
||||
<H3>Implementation</H3>
|
||||
A Python ISAPI filter extension consists of 2 main components:
|
||||
<UL>
|
||||
<LI>A DLL used by ISAPI to interface with Python.</LI>
|
||||
<LI>A Python script used by that DLL to implement the filter or extension
|
||||
functionality</LI>
|
||||
</UL>
|
||||
|
||||
<h4>Extension DLL</h4>
|
||||
The DLL is usually managed automatically by the isapi.install module. As the
|
||||
Python script for the extension is installed, a generic DLL provided with
|
||||
the isapi package is installed next to the script, and IIS configured to
|
||||
use this DLL.
|
||||
<p>
|
||||
The name of the DLL always has the same base name as the Python script, but
|
||||
with a leading underscore (_), and an extension of .dll. For example, the
|
||||
sample "redirector.py" will, when installed, have "_redirector.dll" created
|
||||
in the same directory.
|
||||
<p/>
|
||||
The Python script may provide 2 entry points - methods named __FilterFactory__
|
||||
and __ExtensionFactory__, both taking no arguments and returning a filter or
|
||||
extension object.
|
||||
|
||||
<h3>Using py2exe and the isapi package</h3>
|
||||
You can instruct py2exe to create a 'frozen' Python ISAPI filter/extension.
|
||||
In this case, py2exe will create a package with everything you need in one
|
||||
directory, and the Python source file embedded in the .zip file.
|
||||
<p>
|
||||
In general, you will want to build a seperate installation executable along
|
||||
with the ISAPI extension. This executable will be built from the same script.
|
||||
See the ISAPI sample in the py2exe distribution.
|
|
@ -1,730 +0,0 @@
|
|||
"""Installation utilities for Python ISAPI filters and extensions."""
|
||||
|
||||
# this code adapted from "Tomcat JK2 ISAPI redirector", part of Apache
|
||||
# Created July 2004, Mark Hammond.
|
||||
import sys, os, imp, shutil, stat
|
||||
import operator
|
||||
from win32com.client import GetObject, Dispatch
|
||||
from win32com.client.gencache import EnsureModule, EnsureDispatch
|
||||
import win32api
|
||||
import pythoncom
|
||||
import winerror
|
||||
import traceback
|
||||
|
||||
_APP_INPROC = 0
|
||||
_APP_OUTPROC = 1
|
||||
_APP_POOLED = 2
|
||||
_IIS_OBJECT = "IIS://LocalHost/W3SVC"
|
||||
_IIS_SERVER = "IIsWebServer"
|
||||
_IIS_WEBDIR = "IIsWebDirectory"
|
||||
_IIS_WEBVIRTUALDIR = "IIsWebVirtualDir"
|
||||
_IIS_FILTERS = "IIsFilters"
|
||||
_IIS_FILTER = "IIsFilter"
|
||||
|
||||
_DEFAULT_SERVER_NAME = "Default Web Site"
|
||||
_DEFAULT_HEADERS = "X-Powered-By: Python"
|
||||
_DEFAULT_PROTECTION = _APP_POOLED
|
||||
|
||||
# Default is for 'execute' only access - ie, only the extension
|
||||
# can be used. This can be overridden via your install script.
|
||||
_DEFAULT_ACCESS_EXECUTE = True
|
||||
_DEFAULT_ACCESS_READ = False
|
||||
_DEFAULT_ACCESS_WRITE = False
|
||||
_DEFAULT_ACCESS_SCRIPT = False
|
||||
_DEFAULT_CONTENT_INDEXED = False
|
||||
_DEFAULT_ENABLE_DIR_BROWSING = False
|
||||
_DEFAULT_ENABLE_DEFAULT_DOC = False
|
||||
|
||||
_extensions = [ext for ext, _, _ in imp.get_suffixes()]
|
||||
is_debug_build = '_d.pyd' in _extensions
|
||||
|
||||
this_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
class FilterParameters:
|
||||
Name = None
|
||||
Description = None
|
||||
Path = None
|
||||
Server = None
|
||||
# Params that control if/how AddExtensionFile is called.
|
||||
AddExtensionFile = True
|
||||
AddExtensionFile_Enabled = True
|
||||
AddExtensionFile_GroupID = None # defaults to Name
|
||||
AddExtensionFile_CanDelete = True
|
||||
AddExtensionFile_Description = None # defaults to Description.
|
||||
|
||||
def __init__(self, **kw):
|
||||
self.__dict__.update(kw)
|
||||
|
||||
class VirtualDirParameters:
|
||||
Name = None # Must be provided.
|
||||
Description = None # defaults to Name
|
||||
AppProtection = _DEFAULT_PROTECTION
|
||||
Headers = _DEFAULT_HEADERS
|
||||
Path = None # defaults to WWW root.
|
||||
Type = _IIS_WEBVIRTUALDIR
|
||||
AccessExecute = _DEFAULT_ACCESS_EXECUTE
|
||||
AccessRead = _DEFAULT_ACCESS_READ
|
||||
AccessWrite = _DEFAULT_ACCESS_WRITE
|
||||
AccessScript = _DEFAULT_ACCESS_SCRIPT
|
||||
ContentIndexed = _DEFAULT_CONTENT_INDEXED
|
||||
EnableDirBrowsing = _DEFAULT_ENABLE_DIR_BROWSING
|
||||
EnableDefaultDoc = _DEFAULT_ENABLE_DEFAULT_DOC
|
||||
DefaultDoc = None # Only set in IIS if not None
|
||||
ScriptMaps = []
|
||||
ScriptMapUpdate = "end" # can be 'start', 'end', 'replace'
|
||||
Server = None
|
||||
|
||||
def __init__(self, **kw):
|
||||
self.__dict__.update(kw)
|
||||
|
||||
def is_root(self):
|
||||
"This virtual directory is a root directory if parent and name are blank"
|
||||
parent, name = self.split_path()
|
||||
return not parent and not name
|
||||
|
||||
def split_path(self):
|
||||
return split_path(self.Name)
|
||||
|
||||
class ScriptMapParams:
|
||||
Extension = None
|
||||
Module = None
|
||||
Flags = 5
|
||||
Verbs = ""
|
||||
# Params that control if/how AddExtensionFile is called.
|
||||
AddExtensionFile = True
|
||||
AddExtensionFile_Enabled = True
|
||||
AddExtensionFile_GroupID = None # defaults to Name
|
||||
AddExtensionFile_CanDelete = True
|
||||
AddExtensionFile_Description = None # defaults to Description.
|
||||
def __init__(self, **kw):
|
||||
self.__dict__.update(kw)
|
||||
|
||||
def __str__(self):
|
||||
"Format this parameter suitable for IIS"
|
||||
items = [self.Extension, self.Module, self.Flags]
|
||||
# IIS gets upset if there is a trailing verb comma, but no verbs
|
||||
if self.Verbs:
|
||||
items.append(self.Verbs)
|
||||
items = [str(item) for item in items]
|
||||
return ','.join(items)
|
||||
|
||||
class ISAPIParameters:
|
||||
ServerName = _DEFAULT_SERVER_NAME
|
||||
# Description = None
|
||||
Filters = []
|
||||
VirtualDirs = []
|
||||
def __init__(self, **kw):
|
||||
self.__dict__.update(kw)
|
||||
|
||||
verbose = 1 # The level - 0 is quiet.
|
||||
def log(level, what):
|
||||
if verbose >= level:
|
||||
print(what)
|
||||
|
||||
# Convert an ADSI COM exception to the Win32 error code embedded in it.
|
||||
def _GetWin32ErrorCode(com_exc):
|
||||
hr = com_exc.hresult
|
||||
# If we have more details in the 'excepinfo' struct, use it.
|
||||
if com_exc.excepinfo:
|
||||
hr = com_exc.excepinfo[-1]
|
||||
if winerror.HRESULT_FACILITY(hr) != winerror.FACILITY_WIN32:
|
||||
raise
|
||||
return winerror.SCODE_CODE(hr)
|
||||
|
||||
class InstallationError(Exception): pass
|
||||
class ItemNotFound(InstallationError): pass
|
||||
class ConfigurationError(InstallationError): pass
|
||||
|
||||
def FindPath(options, server, name):
|
||||
if name.lower().startswith("iis://"):
|
||||
return name
|
||||
else:
|
||||
if name and name[0] != "/":
|
||||
name = "/"+name
|
||||
return FindWebServer(options, server)+"/ROOT"+name
|
||||
|
||||
def LocateWebServerPath(description):
|
||||
"""
|
||||
Find an IIS web server whose name or comment matches the provided
|
||||
description (case-insensitive).
|
||||
|
||||
>>> LocateWebServerPath('Default Web Site') # doctest: +SKIP
|
||||
|
||||
or
|
||||
|
||||
>>> LocateWebServerPath('1') #doctest: +SKIP
|
||||
"""
|
||||
assert len(description) >= 1, "Server name or comment is required"
|
||||
iis = GetObject(_IIS_OBJECT)
|
||||
description = description.lower().strip()
|
||||
for site in iis:
|
||||
# Name is generally a number, but no need to assume that.
|
||||
site_attributes = [getattr(site, attr, "").lower().strip()
|
||||
for attr in ("Name", "ServerComment")]
|
||||
if description in site_attributes:
|
||||
return site.AdsPath
|
||||
msg = "No web sites match the description '%s'" % description
|
||||
raise ItemNotFound(msg)
|
||||
|
||||
def GetWebServer(description = None):
|
||||
"""
|
||||
Load the web server instance (COM object) for a given instance
|
||||
or description.
|
||||
If None is specified, the default website is retrieved (indicated
|
||||
by the identifier 1.
|
||||
"""
|
||||
description = description or "1"
|
||||
path = LocateWebServerPath(description)
|
||||
server = LoadWebServer(path)
|
||||
return server
|
||||
|
||||
def LoadWebServer(path):
|
||||
try:
|
||||
server = GetObject(path)
|
||||
except pythoncom.com_error as details:
|
||||
msg = details.strerror
|
||||
if exc.excepinfo and exc.excepinfo[2]:
|
||||
msg = exc.excepinfo[2]
|
||||
msg = "WebServer %s: %s" % (path, msg)
|
||||
raise ItemNotFound(msg)
|
||||
return server
|
||||
|
||||
def FindWebServer(options, server_desc):
|
||||
"""
|
||||
Legacy function to allow options to define a .server property
|
||||
to override the other parameter. Use GetWebServer instead.
|
||||
"""
|
||||
# options takes precedence
|
||||
server_desc = options.server or server_desc
|
||||
# make sure server_desc is unicode (could be mbcs if passed in
|
||||
# sys.argv).
|
||||
if server_desc and not isinstance(server_desc, str):
|
||||
server_desc = server_desc.decode('mbcs')
|
||||
|
||||
# get the server (if server_desc is None, the default site is acquired)
|
||||
server = GetWebServer(server_desc)
|
||||
return server.adsPath
|
||||
|
||||
def split_path(path):
|
||||
"""
|
||||
Get the parent path and basename.
|
||||
|
||||
>>> split_path('/')
|
||||
['', '']
|
||||
|
||||
>>> split_path('')
|
||||
['', '']
|
||||
|
||||
>>> split_path('foo')
|
||||
['', 'foo']
|
||||
|
||||
>>> split_path('/foo')
|
||||
['', 'foo']
|
||||
|
||||
>>> split_path('/foo/bar')
|
||||
['/foo', 'bar']
|
||||
|
||||
>>> split_path('foo/bar')
|
||||
['/foo', 'bar']
|
||||
"""
|
||||
|
||||
if not path.startswith('/'): path = '/' + path
|
||||
return path.rsplit('/', 1)
|
||||
|
||||
def _CreateDirectory(iis_dir, name, params):
|
||||
# We used to go to lengths to keep an existing virtual directory
|
||||
# in place. However, in some cases the existing directories got
|
||||
# into a bad state, and an update failed to get them working.
|
||||
# So we nuke it first. If this is a problem, we could consider adding
|
||||
# a --keep-existing option.
|
||||
try:
|
||||
# Also seen the Class change to a generic IISObject - so nuke
|
||||
# *any* existing object, regardless of Class
|
||||
assert name.strip("/"), "mustn't delete the root!"
|
||||
iis_dir.Delete('', name)
|
||||
log(2, "Deleted old directory '%s'" % (name,))
|
||||
except pythoncom.com_error:
|
||||
pass
|
||||
|
||||
newDir = iis_dir.Create(params.Type, name)
|
||||
log(2, "Creating new directory '%s' in %s..." % (name,iis_dir.Name))
|
||||
|
||||
friendly = params.Description or params.Name
|
||||
newDir.AppFriendlyName = friendly
|
||||
|
||||
# Note that the new directory won't be visible in the IIS UI
|
||||
# unless the directory exists on the filesystem.
|
||||
try:
|
||||
path = params.Path or iis_dir.Path
|
||||
newDir.Path = path
|
||||
except AttributeError:
|
||||
# If params.Type is IIS_WEBDIRECTORY, an exception is thrown
|
||||
pass
|
||||
newDir.AppCreate2(params.AppProtection)
|
||||
# XXX - note that these Headers only work in IIS6 and earlier. IIS7
|
||||
# only supports them on the w3svc node - not even on individial sites,
|
||||
# let alone individual extensions in the site!
|
||||
if params.Headers:
|
||||
newDir.HttpCustomHeaders = params.Headers
|
||||
|
||||
log(2, "Setting directory options...")
|
||||
newDir.AccessExecute = params.AccessExecute
|
||||
newDir.AccessRead = params.AccessRead
|
||||
newDir.AccessWrite = params.AccessWrite
|
||||
newDir.AccessScript = params.AccessScript
|
||||
newDir.ContentIndexed = params.ContentIndexed
|
||||
newDir.EnableDirBrowsing = params.EnableDirBrowsing
|
||||
newDir.EnableDefaultDoc = params.EnableDefaultDoc
|
||||
if params.DefaultDoc is not None:
|
||||
newDir.DefaultDoc = params.DefaultDoc
|
||||
newDir.SetInfo()
|
||||
return newDir
|
||||
|
||||
|
||||
def CreateDirectory(params, options):
|
||||
_CallHook(params, "PreInstall", options)
|
||||
if not params.Name:
|
||||
raise ConfigurationError("No Name param")
|
||||
parent, name = params.split_path()
|
||||
target_dir = GetObject(FindPath(options, params.Server, parent))
|
||||
|
||||
if not params.is_root():
|
||||
target_dir = _CreateDirectory(target_dir, name, params)
|
||||
|
||||
AssignScriptMaps(params.ScriptMaps, target_dir, params.ScriptMapUpdate)
|
||||
|
||||
_CallHook(params, "PostInstall", options, target_dir)
|
||||
log(1, "Configured Virtual Directory: %s" % (params.Name,))
|
||||
return target_dir
|
||||
|
||||
def AssignScriptMaps(script_maps, target, update='replace'):
|
||||
"""Updates IIS with the supplied script map information.
|
||||
|
||||
script_maps is a list of ScriptMapParameter objects
|
||||
|
||||
target is an IIS Virtual Directory to assign the script maps to
|
||||
|
||||
update is a string indicating how to update the maps, one of ('start',
|
||||
'end', or 'replace')
|
||||
"""
|
||||
# determine which function to use to assign script maps
|
||||
script_map_func = '_AssignScriptMaps' + update.capitalize()
|
||||
try:
|
||||
script_map_func = eval(script_map_func)
|
||||
except NameError:
|
||||
msg = "Unknown ScriptMapUpdate option '%s'" % update
|
||||
raise ConfigurationError(msg)
|
||||
# use the str method to format the script maps for IIS
|
||||
script_maps = [str(s) for s in script_maps]
|
||||
# call the correct function
|
||||
script_map_func(target, script_maps)
|
||||
target.SetInfo()
|
||||
|
||||
def get_unique_items(sequence, reference):
|
||||
"Return items in sequence that can't be found in reference."
|
||||
return tuple([item for item in sequence if item not in reference])
|
||||
|
||||
def _AssignScriptMapsReplace(target, script_maps):
|
||||
target.ScriptMaps = script_maps
|
||||
|
||||
def _AssignScriptMapsEnd(target, script_maps):
|
||||
unique_new_maps = get_unique_items(script_maps, target.ScriptMaps)
|
||||
target.ScriptMaps = target.ScriptMaps + unique_new_maps
|
||||
|
||||
def _AssignScriptMapsStart(target, script_maps):
|
||||
unique_new_maps = get_unique_items(script_maps, target.ScriptMaps)
|
||||
target.ScriptMaps = unique_new_maps + target.ScriptMaps
|
||||
|
||||
def CreateISAPIFilter(filterParams, options):
|
||||
server = FindWebServer(options, filterParams.Server)
|
||||
_CallHook(filterParams, "PreInstall", options)
|
||||
try:
|
||||
filters = GetObject(server+"/Filters")
|
||||
except pythoncom.com_error as exc:
|
||||
# Brand new sites don't have the '/Filters' collection - create it.
|
||||
# Any errors other than 'not found' we shouldn't ignore.
|
||||
if winerror.HRESULT_FACILITY(exc.hresult) != winerror.FACILITY_WIN32 or \
|
||||
winerror.HRESULT_CODE(exc.hresult) != winerror.ERROR_PATH_NOT_FOUND:
|
||||
raise
|
||||
server_ob = GetObject(server)
|
||||
filters = server_ob.Create(_IIS_FILTERS, "Filters")
|
||||
filters.FilterLoadOrder = ""
|
||||
filters.SetInfo()
|
||||
|
||||
# As for VirtualDir, delete an existing one.
|
||||
assert filterParams.Name.strip("/"), "mustn't delete the root!"
|
||||
try:
|
||||
filters.Delete(_IIS_FILTER, filterParams.Name)
|
||||
log(2, "Deleted old filter '%s'" % (filterParams.Name,))
|
||||
except pythoncom.com_error:
|
||||
pass
|
||||
newFilter = filters.Create(_IIS_FILTER, filterParams.Name)
|
||||
log(2, "Created new ISAPI filter...")
|
||||
assert os.path.isfile(filterParams.Path)
|
||||
newFilter.FilterPath = filterParams.Path
|
||||
newFilter.FilterDescription = filterParams.Description
|
||||
newFilter.SetInfo()
|
||||
load_order = [b.strip() for b in filters.FilterLoadOrder.split(",") if b]
|
||||
if filterParams.Name not in load_order:
|
||||
load_order.append(filterParams.Name)
|
||||
filters.FilterLoadOrder = ",".join(load_order)
|
||||
filters.SetInfo()
|
||||
_CallHook(filterParams, "PostInstall", options, newFilter)
|
||||
log (1, "Configured Filter: %s" % (filterParams.Name,))
|
||||
return newFilter
|
||||
|
||||
def DeleteISAPIFilter(filterParams, options):
|
||||
_CallHook(filterParams, "PreRemove", options)
|
||||
server = FindWebServer(options, filterParams.Server)
|
||||
ob_path = server+"/Filters"
|
||||
try:
|
||||
filters = GetObject(ob_path)
|
||||
except pythoncom.com_error as details:
|
||||
# failure to open the filters just means a totally clean IIS install
|
||||
# (IIS5 at least has no 'Filters' key when freshly installed).
|
||||
log(2, "ISAPI filter path '%s' did not exist." % (ob_path,))
|
||||
return
|
||||
try:
|
||||
assert filterParams.Name.strip("/"), "mustn't delete the root!"
|
||||
filters.Delete(_IIS_FILTER, filterParams.Name)
|
||||
log(2, "Deleted ISAPI filter '%s'" % (filterParams.Name,))
|
||||
except pythoncom.com_error as details:
|
||||
rc = _GetWin32ErrorCode(details)
|
||||
if rc != winerror.ERROR_PATH_NOT_FOUND:
|
||||
raise
|
||||
log(2, "ISAPI filter '%s' did not exist." % (filterParams.Name,))
|
||||
# Remove from the load order
|
||||
load_order = [b.strip() for b in filters.FilterLoadOrder.split(",") if b]
|
||||
if filterParams.Name in load_order:
|
||||
load_order.remove(filterParams.Name)
|
||||
filters.FilterLoadOrder = ",".join(load_order)
|
||||
filters.SetInfo()
|
||||
_CallHook(filterParams, "PostRemove", options)
|
||||
log (1, "Deleted Filter: %s" % (filterParams.Name,))
|
||||
|
||||
def _AddExtensionFile(module, def_groupid, def_desc, params, options):
|
||||
group_id = params.AddExtensionFile_GroupID or def_groupid
|
||||
desc = params.AddExtensionFile_Description or def_desc
|
||||
try:
|
||||
ob = GetObject(_IIS_OBJECT)
|
||||
ob.AddExtensionFile(module,
|
||||
params.AddExtensionFile_Enabled,
|
||||
group_id,
|
||||
params.AddExtensionFile_CanDelete,
|
||||
desc)
|
||||
log(2, "Added extension file '%s' (%s)" % (module, desc))
|
||||
except (pythoncom.com_error, AttributeError) as details:
|
||||
# IIS5 always fails. Probably should upgrade this to
|
||||
# complain more loudly if IIS6 fails.
|
||||
log(2, "Failed to add extension file '%s': %s" % (module, details))
|
||||
|
||||
def AddExtensionFiles(params, options):
|
||||
"""Register the modules used by the filters/extensions as a trusted
|
||||
'extension module' - required by the default IIS6 security settings."""
|
||||
# Add each module only once.
|
||||
added = {}
|
||||
for vd in params.VirtualDirs:
|
||||
for smp in vd.ScriptMaps:
|
||||
if smp.Module not in added and smp.AddExtensionFile:
|
||||
_AddExtensionFile(smp.Module, vd.Name, vd.Description, smp,
|
||||
options)
|
||||
added[smp.Module] = True
|
||||
|
||||
for fd in params.Filters:
|
||||
if fd.Path not in added and fd.AddExtensionFile:
|
||||
_AddExtensionFile(fd.Path, fd.Name, fd.Description, fd, options)
|
||||
added[fd.Path] = True
|
||||
|
||||
def _DeleteExtensionFileRecord(module, options):
|
||||
try:
|
||||
ob = GetObject(_IIS_OBJECT)
|
||||
ob.DeleteExtensionFileRecord(module)
|
||||
log(2, "Deleted extension file record for '%s'" % module)
|
||||
except (pythoncom.com_error, AttributeError) as details:
|
||||
log(2, "Failed to remove extension file '%s': %s" % (module, details))
|
||||
|
||||
def DeleteExtensionFileRecords(params, options):
|
||||
deleted = {} # only remove each .dll once.
|
||||
for vd in params.VirtualDirs:
|
||||
for smp in vd.ScriptMaps:
|
||||
if smp.Module not in deleted and smp.AddExtensionFile:
|
||||
_DeleteExtensionFileRecord(smp.Module, options)
|
||||
deleted[smp.Module] = True
|
||||
|
||||
for filter_def in params.Filters:
|
||||
if filter_def.Path not in deleted and filter_def.AddExtensionFile:
|
||||
_DeleteExtensionFileRecord(filter_def.Path, options)
|
||||
deleted[filter_def.Path] = True
|
||||
|
||||
def CheckLoaderModule(dll_name):
|
||||
suffix = ""
|
||||
if is_debug_build: suffix = "_d"
|
||||
template = os.path.join(this_dir,
|
||||
"PyISAPI_loader" + suffix + ".dll")
|
||||
if not os.path.isfile(template):
|
||||
raise ConfigurationError(
|
||||
"Template loader '%s' does not exist" % (template,))
|
||||
# We can't do a simple "is newer" check, as the DLL is specific to the
|
||||
# Python version. So we check the date-time and size are identical,
|
||||
# and skip the copy in that case.
|
||||
src_stat = os.stat(template)
|
||||
try:
|
||||
dest_stat = os.stat(dll_name)
|
||||
except os.error:
|
||||
same = 0
|
||||
else:
|
||||
same = src_stat[stat.ST_SIZE]==dest_stat[stat.ST_SIZE] and \
|
||||
src_stat[stat.ST_MTIME]==dest_stat[stat.ST_MTIME]
|
||||
if not same:
|
||||
log(2, "Updating %s->%s" % (template, dll_name))
|
||||
shutil.copyfile(template, dll_name)
|
||||
shutil.copystat(template, dll_name)
|
||||
else:
|
||||
log(2, "%s is up to date." % (dll_name,))
|
||||
|
||||
def _CallHook(ob, hook_name, options, *extra_args):
|
||||
func = getattr(ob, hook_name, None)
|
||||
if func is not None:
|
||||
args = (ob,options) + extra_args
|
||||
func(*args)
|
||||
|
||||
def Install(params, options):
|
||||
_CallHook(params, "PreInstall", options)
|
||||
for vd in params.VirtualDirs:
|
||||
CreateDirectory(vd, options)
|
||||
|
||||
for filter_def in params.Filters:
|
||||
CreateISAPIFilter(filter_def, options)
|
||||
|
||||
AddExtensionFiles(params, options)
|
||||
|
||||
_CallHook(params, "PostInstall", options)
|
||||
|
||||
def RemoveDirectory(params, options):
|
||||
if params.is_root():
|
||||
return
|
||||
try:
|
||||
directory = GetObject(FindPath(options, params.Server, params.Name))
|
||||
except pythoncom.com_error as details:
|
||||
rc = _GetWin32ErrorCode(details)
|
||||
if rc != winerror.ERROR_PATH_NOT_FOUND:
|
||||
raise
|
||||
log(2, "VirtualDirectory '%s' did not exist" % params.Name)
|
||||
directory = None
|
||||
if directory is not None:
|
||||
# Be robust should IIS get upset about unloading.
|
||||
try:
|
||||
directory.AppUnLoad()
|
||||
except:
|
||||
exc_val = sys.exc_info()[1]
|
||||
log(2, "AppUnLoad() for %s failed: %s" % (params.Name, exc_val))
|
||||
# Continue trying to delete it.
|
||||
try:
|
||||
parent = GetObject(directory.Parent)
|
||||
parent.Delete(directory.Class, directory.Name)
|
||||
log (1, "Deleted Virtual Directory: %s" % (params.Name,))
|
||||
except:
|
||||
exc_val = sys.exc_info()[1]
|
||||
log(1, "Failed to remove directory %s: %s" % (params.Name, exc_val))
|
||||
|
||||
def RemoveScriptMaps(vd_params, options):
|
||||
"Remove script maps from the already installed virtual directory"
|
||||
parent, name = vd_params.split_path()
|
||||
target_dir = GetObject(FindPath(options, vd_params.Server, parent))
|
||||
installed_maps = list(target_dir.ScriptMaps)
|
||||
for _map in map(str, vd_params.ScriptMaps):
|
||||
if _map in installed_maps:
|
||||
installed_maps.remove(_map)
|
||||
target_dir.ScriptMaps = installed_maps
|
||||
target_dir.SetInfo()
|
||||
|
||||
def Uninstall(params, options):
|
||||
_CallHook(params, "PreRemove", options)
|
||||
|
||||
DeleteExtensionFileRecords(params, options)
|
||||
|
||||
for vd in params.VirtualDirs:
|
||||
_CallHook(vd, "PreRemove", options)
|
||||
|
||||
RemoveDirectory(vd, options)
|
||||
if vd.is_root():
|
||||
# if this is installed to the root virtual directory, we can't delete it
|
||||
# so remove the script maps.
|
||||
RemoveScriptMaps(vd, options)
|
||||
|
||||
_CallHook(vd, "PostRemove", options)
|
||||
|
||||
for filter_def in params.Filters:
|
||||
DeleteISAPIFilter(filter_def, options)
|
||||
_CallHook(params, "PostRemove", options)
|
||||
|
||||
# Patch up any missing module names in the params, replacing them with
|
||||
# the DLL name that hosts this extension/filter.
|
||||
def _PatchParamsModule(params, dll_name, file_must_exist = True):
|
||||
if file_must_exist:
|
||||
if not os.path.isfile(dll_name):
|
||||
raise ConfigurationError("%s does not exist" % (dll_name,))
|
||||
|
||||
# Patch up all references to the DLL.
|
||||
for f in params.Filters:
|
||||
if f.Path is None: f.Path = dll_name
|
||||
for d in params.VirtualDirs:
|
||||
for sm in d.ScriptMaps:
|
||||
if sm.Module is None: sm.Module = dll_name
|
||||
|
||||
def GetLoaderModuleName(mod_name, check_module = None):
|
||||
# find the name of the DLL hosting us.
|
||||
# By default, this is "_{module_base_name}.dll"
|
||||
if hasattr(sys, "frozen"):
|
||||
# What to do? The .dll knows its name, but this is likely to be
|
||||
# executed via a .exe, which does not know.
|
||||
base, ext = os.path.splitext(mod_name)
|
||||
path, base = os.path.split(base)
|
||||
# handle the common case of 'foo.exe'/'foow.exe'
|
||||
if base.endswith('w'):
|
||||
base = base[:-1]
|
||||
# For py2exe, we have '_foo.dll' as the standard pyisapi loader - but
|
||||
# 'foo.dll' is what we use (it just delegates).
|
||||
# So no leading '_' on the installed name.
|
||||
dll_name = os.path.abspath(os.path.join(path, base + ".dll"))
|
||||
else:
|
||||
base, ext = os.path.splitext(mod_name)
|
||||
path, base = os.path.split(base)
|
||||
dll_name = os.path.abspath(os.path.join(path, "_" + base + ".dll"))
|
||||
# Check we actually have it.
|
||||
if check_module is None: check_module = not hasattr(sys, "frozen")
|
||||
if check_module:
|
||||
CheckLoaderModule(dll_name)
|
||||
return dll_name
|
||||
|
||||
# Note the 'log' params to these 'builtin' args - old versions of pywin32
|
||||
# didn't log at all in this function (by intent; anyone calling this was
|
||||
# responsible). So existing code that calls this function with the old
|
||||
# signature (ie, without a 'log' param) still gets the same behaviour as
|
||||
# before...
|
||||
|
||||
def InstallModule(conf_module_name, params, options, log=lambda *args:None):
|
||||
"Install the extension"
|
||||
if not hasattr(sys, "frozen"):
|
||||
conf_module_name = os.path.abspath(conf_module_name)
|
||||
if not os.path.isfile(conf_module_name):
|
||||
raise ConfigurationError("%s does not exist" % (conf_module_name,))
|
||||
|
||||
loader_dll = GetLoaderModuleName(conf_module_name)
|
||||
_PatchParamsModule(params, loader_dll)
|
||||
Install(params, options)
|
||||
log(1, "Installation complete.")
|
||||
|
||||
def UninstallModule(conf_module_name, params, options, log=lambda *args:None):
|
||||
"Remove the extension"
|
||||
loader_dll = GetLoaderModuleName(conf_module_name, False)
|
||||
_PatchParamsModule(params, loader_dll, False)
|
||||
Uninstall(params, options)
|
||||
log(1, "Uninstallation complete.")
|
||||
|
||||
standard_arguments = {
|
||||
"install" : InstallModule,
|
||||
"remove" : UninstallModule,
|
||||
}
|
||||
|
||||
def build_usage(handler_map):
|
||||
docstrings = [handler.__doc__ for handler in handler_map.values()]
|
||||
all_args = dict(zip(iter(handler_map.keys()), docstrings))
|
||||
arg_names = "|".join(iter(all_args.keys()))
|
||||
usage_string = "%prog [options] [" + arg_names + "]\n"
|
||||
usage_string += "commands:\n"
|
||||
for arg, desc in all_args.items():
|
||||
usage_string += " %-10s: %s" % (arg, desc) + "\n"
|
||||
return usage_string[:-1]
|
||||
|
||||
def MergeStandardOptions(options, params):
|
||||
"""
|
||||
Take an options object generated by the command line and merge
|
||||
the values into the IISParameters object.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# We support 2 ways of extending our command-line/install support.
|
||||
# * Many of the installation items allow you to specify "PreInstall",
|
||||
# "PostInstall", "PreRemove" and "PostRemove" hooks
|
||||
# All hooks are called with the 'params' object being operated on, and
|
||||
# the 'optparser' options for this session (ie, the command-line options)
|
||||
# PostInstall for VirtualDirectories and Filters both have an additional
|
||||
# param - the ADSI object just created.
|
||||
# * You can pass your own option parser for us to use, and/or define a map
|
||||
# with your own custom arg handlers. It is a map of 'arg'->function.
|
||||
# The function is called with (options, log_fn, arg). The function's
|
||||
# docstring is used in the usage output.
|
||||
def HandleCommandLine(params, argv=None, conf_module_name = None,
|
||||
default_arg = "install",
|
||||
opt_parser = None, custom_arg_handlers = {}):
|
||||
"""Perform installation or removal of an ISAPI filter or extension.
|
||||
|
||||
This module handles standard command-line options and configuration
|
||||
information, and installs, removes or updates the configuration of an
|
||||
ISAPI filter or extension.
|
||||
|
||||
You must pass your configuration information in params - all other
|
||||
arguments are optional, and allow you to configure the installation
|
||||
process.
|
||||
"""
|
||||
global verbose
|
||||
from optparse import OptionParser
|
||||
|
||||
argv = argv or sys.argv
|
||||
if not conf_module_name:
|
||||
conf_module_name = sys.argv[0]
|
||||
# convert to a long name so that if we were somehow registered with
|
||||
# the "short" version but unregistered with the "long" version we
|
||||
# still work (that will depend on exactly how the installer was
|
||||
# started)
|
||||
try:
|
||||
conf_module_name = win32api.GetLongPathName(conf_module_name)
|
||||
except win32api.error as exc:
|
||||
log(2, "Couldn't determine the long name for %r: %s" %
|
||||
(conf_module_name, exc))
|
||||
|
||||
if opt_parser is None:
|
||||
# Build our own parser.
|
||||
parser = OptionParser(usage='')
|
||||
else:
|
||||
# The caller is providing their own filter, presumably with their
|
||||
# own options all setup.
|
||||
parser = opt_parser
|
||||
|
||||
# build a usage string if we don't have one.
|
||||
if not parser.get_usage():
|
||||
all_handlers = standard_arguments.copy()
|
||||
all_handlers.update(custom_arg_handlers)
|
||||
parser.set_usage(build_usage(all_handlers))
|
||||
|
||||
# allow the user to use uninstall as a synonym for remove if it wasn't
|
||||
# defined by the custom arg handlers.
|
||||
all_handlers.setdefault('uninstall', all_handlers['remove'])
|
||||
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_false", dest="verbose", default=True,
|
||||
help="don't print status messages to stdout")
|
||||
parser.add_option("-v", "--verbosity", action="count",
|
||||
dest="verbose", default=1,
|
||||
help="increase the verbosity of status messages")
|
||||
parser.add_option("", "--server", action="store",
|
||||
help="Specifies the IIS server to install/uninstall on." \
|
||||
" Default is '%s/1'" % (_IIS_OBJECT,))
|
||||
|
||||
(options, args) = parser.parse_args(argv[1:])
|
||||
MergeStandardOptions(options, params)
|
||||
verbose = options.verbose
|
||||
if not args:
|
||||
args = [default_arg]
|
||||
try:
|
||||
for arg in args:
|
||||
handler = all_handlers[arg]
|
||||
handler(conf_module_name, params, options, log)
|
||||
except (ItemNotFound, InstallationError) as details:
|
||||
if options.verbose > 1:
|
||||
traceback.print_exc()
|
||||
print("%s: %s" % (details.__class__.__name__, details))
|
||||
except KeyError:
|
||||
parser.error("Invalid arg '%s'" % arg)
|
|
@ -1,120 +0,0 @@
|
|||
"""Constants needed by ISAPI filters and extensions."""
|
||||
# ======================================================================
|
||||
# Copyright 2002-2003 by Blackdog Software Pty Ltd.
|
||||
#
|
||||
# All Rights Reserved
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and
|
||||
# its documentation for any purpose and without fee is hereby
|
||||
# granted, provided that the above copyright notice appear in all
|
||||
# copies and that both that copyright notice and this permission
|
||||
# notice appear in supporting documentation, and that the name of
|
||||
# Blackdog Software not be used in advertising or publicity pertaining to
|
||||
# distribution of the software without specific, written prior
|
||||
# permission.
|
||||
#
|
||||
# BLACKDOG SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
||||
# NO EVENT SHALL BLACKDOG SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
# ======================================================================
|
||||
|
||||
# HTTP reply codes
|
||||
|
||||
HTTP_CONTINUE = 100
|
||||
HTTP_SWITCHING_PROTOCOLS = 101
|
||||
HTTP_PROCESSING = 102
|
||||
HTTP_OK = 200
|
||||
HTTP_CREATED = 201
|
||||
HTTP_ACCEPTED = 202
|
||||
HTTP_NON_AUTHORITATIVE = 203
|
||||
HTTP_NO_CONTENT = 204
|
||||
HTTP_RESET_CONTENT = 205
|
||||
HTTP_PARTIAL_CONTENT = 206
|
||||
HTTP_MULTI_STATUS = 207
|
||||
HTTP_MULTIPLE_CHOICES = 300
|
||||
HTTP_MOVED_PERMANENTLY = 301
|
||||
HTTP_MOVED_TEMPORARILY = 302
|
||||
HTTP_SEE_OTHER = 303
|
||||
HTTP_NOT_MODIFIED = 304
|
||||
HTTP_USE_PROXY = 305
|
||||
HTTP_TEMPORARY_REDIRECT = 307
|
||||
HTTP_BAD_REQUEST = 400
|
||||
HTTP_UNAUTHORIZED = 401
|
||||
HTTP_PAYMENT_REQUIRED = 402
|
||||
HTTP_FORBIDDEN = 403
|
||||
HTTP_NOT_FOUND = 404
|
||||
HTTP_METHOD_NOT_ALLOWED = 405
|
||||
HTTP_NOT_ACCEPTABLE = 406
|
||||
HTTP_PROXY_AUTHENTICATION_REQUIRED= 407
|
||||
HTTP_REQUEST_TIME_OUT = 408
|
||||
HTTP_CONFLICT = 409
|
||||
HTTP_GONE = 410
|
||||
HTTP_LENGTH_REQUIRED = 411
|
||||
HTTP_PRECONDITION_FAILED = 412
|
||||
HTTP_REQUEST_ENTITY_TOO_LARGE = 413
|
||||
HTTP_REQUEST_URI_TOO_LARGE = 414
|
||||
HTTP_UNSUPPORTED_MEDIA_TYPE = 415
|
||||
HTTP_RANGE_NOT_SATISFIABLE = 416
|
||||
HTTP_EXPECTATION_FAILED = 417
|
||||
HTTP_UNPROCESSABLE_ENTITY = 422
|
||||
HTTP_INTERNAL_SERVER_ERROR = 500
|
||||
HTTP_NOT_IMPLEMENTED = 501
|
||||
HTTP_BAD_GATEWAY = 502
|
||||
HTTP_SERVICE_UNAVAILABLE = 503
|
||||
HTTP_GATEWAY_TIME_OUT = 504
|
||||
HTTP_VERSION_NOT_SUPPORTED = 505
|
||||
HTTP_VARIANT_ALSO_VARIES = 506
|
||||
|
||||
HSE_STATUS_SUCCESS = 1
|
||||
HSE_STATUS_SUCCESS_AND_KEEP_CONN = 2
|
||||
HSE_STATUS_PENDING = 3
|
||||
HSE_STATUS_ERROR = 4
|
||||
|
||||
SF_NOTIFY_SECURE_PORT = 0x00000001
|
||||
SF_NOTIFY_NONSECURE_PORT = 0x00000002
|
||||
SF_NOTIFY_READ_RAW_DATA = 0x00008000
|
||||
SF_NOTIFY_PREPROC_HEADERS = 0x00004000
|
||||
SF_NOTIFY_AUTHENTICATION = 0x00002000
|
||||
SF_NOTIFY_URL_MAP = 0x00001000
|
||||
SF_NOTIFY_ACCESS_DENIED = 0x00000800
|
||||
SF_NOTIFY_SEND_RESPONSE = 0x00000040
|
||||
SF_NOTIFY_SEND_RAW_DATA = 0x00000400
|
||||
SF_NOTIFY_LOG = 0x00000200
|
||||
SF_NOTIFY_END_OF_REQUEST = 0x00000080
|
||||
SF_NOTIFY_END_OF_NET_SESSION = 0x00000100
|
||||
|
||||
SF_NOTIFY_ORDER_HIGH = 0x00080000
|
||||
SF_NOTIFY_ORDER_MEDIUM = 0x00040000
|
||||
SF_NOTIFY_ORDER_LOW = 0x00020000
|
||||
SF_NOTIFY_ORDER_DEFAULT = SF_NOTIFY_ORDER_LOW
|
||||
|
||||
SF_NOTIFY_ORDER_MASK = (SF_NOTIFY_ORDER_HIGH | \
|
||||
SF_NOTIFY_ORDER_MEDIUM | \
|
||||
SF_NOTIFY_ORDER_LOW)
|
||||
|
||||
SF_STATUS_REQ_FINISHED = 134217728 # 0x8000000
|
||||
SF_STATUS_REQ_FINISHED_KEEP_CONN = 134217728 + 1
|
||||
SF_STATUS_REQ_NEXT_NOTIFICATION = 134217728 + 2
|
||||
SF_STATUS_REQ_HANDLED_NOTIFICATION = 134217728 + 3
|
||||
SF_STATUS_REQ_ERROR = 134217728 + 4
|
||||
SF_STATUS_REQ_READ_NEXT = 134217728 + 5
|
||||
|
||||
HSE_IO_SYNC = 0x00000001 # for WriteClient
|
||||
HSE_IO_ASYNC = 0x00000002 # for WriteClient/TF/EU
|
||||
HSE_IO_DISCONNECT_AFTER_SEND = 0x00000004 # for TF
|
||||
HSE_IO_SEND_HEADERS = 0x00000008 # for TF
|
||||
HSE_IO_NODELAY = 0x00001000 # turn off nagling
|
||||
# These two are only used by VectorSend
|
||||
HSE_IO_FINAL_SEND = 0x00000010
|
||||
HSE_IO_CACHE_RESPONSE = 0x00000020
|
||||
|
||||
HSE_EXEC_URL_NO_HEADERS = 0x02
|
||||
HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR = 0x04
|
||||
HSE_EXEC_URL_IGNORE_VALIDATION_AND_RANGE = 0x10
|
||||
HSE_EXEC_URL_DISABLE_CUSTOM_ERROR = 0x20
|
||||
HSE_EXEC_URL_SSI_CMD = 0x40
|
||||
HSE_EXEC_URL_HTTP_CACHE_ELIGIBLE = 0x80
|
|
@ -1,20 +0,0 @@
|
|||
In this directory you will find examples of ISAPI filters and extensions.
|
||||
|
||||
The filter loading mechanism works like this:
|
||||
* IIS loads the special Python "loader" DLL. This DLL will generally have a
|
||||
leading underscore as part of its name.
|
||||
* This loader DLL looks for a Python module, by removing the first letter of
|
||||
the DLL base name.
|
||||
|
||||
This means that an ISAPI extension module consists of 2 key files - the loader
|
||||
DLL (eg, "_MyIISModule.dll", and a Python module (which for this example
|
||||
would be "MyIISModule.py")
|
||||
|
||||
When you install an ISAPI extension, the installation code checks to see if
|
||||
there is a loader DLL for your implementation file - if one does not exist,
|
||||
or the standard loader is different, it is copied and renamed accordingly.
|
||||
|
||||
We use this mechanism to provide the maximum separation between different
|
||||
Python extensions installed on the same server - otherwise filter order and
|
||||
other tricky IIS semantics would need to be replicated. Also, each filter
|
||||
gets its own thread-pool, etc.
|
|
@ -1,196 +0,0 @@
|
|||
# This extension demonstrates some advanced features of the Python ISAPI
|
||||
# framework.
|
||||
# We demonstrate:
|
||||
# * Reloading your Python module without shutting down IIS (eg, when your
|
||||
# .py implementation file changes.)
|
||||
# * Custom command-line handling - both additional options and commands.
|
||||
# * Using a query string - any part of the URL after a '?' is assumed to
|
||||
# be "variable names" separated by '&' - we will print the values of
|
||||
# these server variables.
|
||||
# * If the tail portion of the URL is "ReportUnhealthy", IIS will be
|
||||
# notified we are unhealthy via a HSE_REQ_REPORT_UNHEALTHY request.
|
||||
# Whether this is acted upon depends on if the IIS health-checking
|
||||
# tools are installed, but you should always see the reason written
|
||||
# to the Windows event log - see the IIS documentation for more.
|
||||
|
||||
from isapi import isapicon
|
||||
from isapi.simple import SimpleExtension
|
||||
import sys, os, stat
|
||||
|
||||
if hasattr(sys, "isapidllhandle"):
|
||||
import win32traceutil
|
||||
|
||||
# Notes on reloading
|
||||
# If your HttpFilterProc or HttpExtensionProc functions raises
|
||||
# 'isapi.InternalReloadException', the framework will not treat it
|
||||
# as an error but instead will terminate your extension, reload your
|
||||
# extension module, re-initialize the instance, and re-issue the request.
|
||||
# The Initialize functions are called with None as their param. The
|
||||
# return code from the terminate function is ignored.
|
||||
#
|
||||
# This is all the framework does to help you. It is up to your code
|
||||
# when you raise this exception. This sample uses a Win32 "find
|
||||
# notification". Whenever windows tells us one of the files in the
|
||||
# directory has changed, we check if the time of our source-file has
|
||||
# changed, and set a flag. Next imcoming request, we check the flag and
|
||||
# raise the special exception if set.
|
||||
#
|
||||
# The end result is that the module is automatically reloaded whenever
|
||||
# the source-file changes - you need take no further action to see your
|
||||
# changes reflected in the running server.
|
||||
|
||||
# The framework only reloads your module - if you have libraries you
|
||||
# depend on and also want reloaded, you must arrange for this yourself.
|
||||
# One way of doing this would be to special case the import of these
|
||||
# modules. Eg:
|
||||
# --
|
||||
# try:
|
||||
# my_module = reload(my_module) # module already imported - reload it
|
||||
# except NameError:
|
||||
# import my_module # first time around - import it.
|
||||
# --
|
||||
# When your module is imported for the first time, the NameError will
|
||||
# be raised, and the module imported. When the ISAPI framework reloads
|
||||
# your module, the existing module will avoid the NameError, and allow
|
||||
# you to reload that module.
|
||||
|
||||
from isapi import InternalReloadException
|
||||
import win32event, win32file, winerror, win32con, threading
|
||||
|
||||
try:
|
||||
reload_counter += 1
|
||||
except NameError:
|
||||
reload_counter = 0
|
||||
|
||||
# A watcher thread that checks for __file__ changing.
|
||||
# When it detects it, it simply sets "change_detected" to true.
|
||||
class ReloadWatcherThread(threading.Thread):
|
||||
def __init__(self):
|
||||
self.change_detected = False
|
||||
self.filename = __file__
|
||||
if self.filename.endswith("c") or self.filename.endswith("o"):
|
||||
self.filename = self.filename[:-1]
|
||||
self.handle = win32file.FindFirstChangeNotification(
|
||||
os.path.dirname(self.filename),
|
||||
False, # watch tree?
|
||||
win32con.FILE_NOTIFY_CHANGE_LAST_WRITE)
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
last_time = os.stat(self.filename)[stat.ST_MTIME]
|
||||
while 1:
|
||||
try:
|
||||
rc = win32event.WaitForSingleObject(self.handle,
|
||||
win32event.INFINITE)
|
||||
win32file.FindNextChangeNotification(self.handle)
|
||||
except win32event.error as details:
|
||||
# handle closed - thread should terminate.
|
||||
if details.winerror != winerror.ERROR_INVALID_HANDLE:
|
||||
raise
|
||||
break
|
||||
this_time = os.stat(self.filename)[stat.ST_MTIME]
|
||||
if this_time != last_time:
|
||||
print("Detected file change - flagging for reload.")
|
||||
self.change_detected = True
|
||||
last_time = this_time
|
||||
|
||||
def stop(self):
|
||||
win32file.FindCloseChangeNotification(self.handle)
|
||||
|
||||
# The ISAPI extension - handles requests in our virtual dir, and sends the
|
||||
# response to the client.
|
||||
class Extension(SimpleExtension):
|
||||
"Python advanced sample Extension"
|
||||
def __init__(self):
|
||||
self.reload_watcher = ReloadWatcherThread()
|
||||
self.reload_watcher.start()
|
||||
|
||||
def HttpExtensionProc(self, ecb):
|
||||
# NOTE: If you use a ThreadPoolExtension, you must still perform
|
||||
# this check in HttpExtensionProc - raising the exception from
|
||||
# The "Dispatch" method will just cause the exception to be
|
||||
# rendered to the browser.
|
||||
if self.reload_watcher.change_detected:
|
||||
print("Doing reload")
|
||||
raise InternalReloadException
|
||||
|
||||
url = ecb.GetServerVariable("UNICODE_URL")
|
||||
if url.endswith("ReportUnhealthy"):
|
||||
ecb.ReportUnhealthy("I'm a little sick")
|
||||
|
||||
ecb.SendResponseHeaders("200 OK", "Content-Type: text/html\r\n\r\n", 0)
|
||||
print("<HTML><BODY>", file=ecb)
|
||||
|
||||
qs = ecb.GetServerVariable("QUERY_STRING")
|
||||
if qs:
|
||||
queries = qs.split("&")
|
||||
print("<PRE>", file=ecb)
|
||||
for q in queries:
|
||||
val = ecb.GetServerVariable(q, '<no such variable>')
|
||||
print("%s=%r" % (q, val), file=ecb)
|
||||
print("</PRE><P/>", file=ecb)
|
||||
|
||||
print("This module has been imported", file=ecb)
|
||||
print("%d times" % (reload_counter,), file=ecb)
|
||||
print("</BODY></HTML>", file=ecb)
|
||||
ecb.close()
|
||||
return isapicon.HSE_STATUS_SUCCESS
|
||||
|
||||
def TerminateExtension(self, status):
|
||||
self.reload_watcher.stop()
|
||||
|
||||
# The entry points for the ISAPI extension.
|
||||
def __ExtensionFactory__():
|
||||
return Extension()
|
||||
|
||||
# Our special command line customization.
|
||||
# Pre-install hook for our virtual directory.
|
||||
def PreInstallDirectory(params, options):
|
||||
# If the user used our special '--description' option,
|
||||
# then we override our default.
|
||||
if options.description:
|
||||
params.Description = options.description
|
||||
|
||||
# Post install hook for our entire script
|
||||
def PostInstall(params, options):
|
||||
print()
|
||||
print("The sample has been installed.")
|
||||
print("Point your browser to /AdvancedPythonSample")
|
||||
print("If you modify the source file and reload the page,")
|
||||
print("you should see the reload counter increment")
|
||||
|
||||
# Handler for our custom 'status' argument.
|
||||
def status_handler(options, log, arg):
|
||||
"Query the status of something"
|
||||
print("Everything seems to be fine!")
|
||||
|
||||
custom_arg_handlers = {"status": status_handler}
|
||||
|
||||
if __name__=='__main__':
|
||||
# If run from the command-line, install ourselves.
|
||||
from isapi.install import *
|
||||
params = ISAPIParameters(PostInstall = PostInstall)
|
||||
# Setup the virtual directories - this is a list of directories our
|
||||
# extension uses - in this case only 1.
|
||||
# Each extension has a "script map" - this is the mapping of ISAPI
|
||||
# extensions.
|
||||
sm = [
|
||||
ScriptMapParams(Extension="*", Flags=0)
|
||||
]
|
||||
vd = VirtualDirParameters(Name="AdvancedPythonSample",
|
||||
Description = Extension.__doc__,
|
||||
ScriptMaps = sm,
|
||||
ScriptMapUpdate = "replace",
|
||||
# specify the pre-install hook.
|
||||
PreInstall = PreInstallDirectory
|
||||
)
|
||||
params.VirtualDirs = [vd]
|
||||
# Setup our custom option parser.
|
||||
from optparse import OptionParser
|
||||
parser = OptionParser('') # blank usage, so isapi sets it.
|
||||
parser.add_option("", "--description",
|
||||
action="store",
|
||||
help="custom description to use for the virtual directory")
|
||||
|
||||
HandleCommandLine(params, opt_parser=parser,
|
||||
custom_arg_handlers = custom_arg_handlers)
|
|
@ -1,109 +0,0 @@
|
|||
# This is a sample ISAPI extension written in Python.
|
||||
#
|
||||
# Please see README.txt in this directory, and specifically the
|
||||
# information about the "loader" DLL - installing this sample will create
|
||||
# "_redirector.dll" in the current directory. The readme explains this.
|
||||
|
||||
# Executing this script (or any server config script) will install the extension
|
||||
# into your web server. As the server executes, the PyISAPI framework will load
|
||||
# this module and create your Extension and Filter objects.
|
||||
|
||||
# This is the simplest possible redirector (or proxy) we can write. The
|
||||
# extension installs with a mask of '*' in the root of the site.
|
||||
# As an added bonus though, we optionally show how, on IIS6 and later, we
|
||||
# can use HSE_ERQ_EXEC_URL to ignore certain requests - in IIS5 and earlier
|
||||
# we can only do this with an ISAPI filter - see redirector_with_filter for
|
||||
# an example. If this sample is run on IIS5 or earlier it simply ignores
|
||||
# any excludes.
|
||||
|
||||
from isapi import isapicon, threaded_extension
|
||||
import sys
|
||||
import traceback
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
# py3k spelling...
|
||||
from urllib.request import urlopen
|
||||
import win32api
|
||||
|
||||
# sys.isapidllhandle will exist when we are loaded by the IIS framework.
|
||||
# In this case we redirect our output to the win32traceutil collector.
|
||||
if hasattr(sys, "isapidllhandle"):
|
||||
import win32traceutil
|
||||
|
||||
# The site we are proxying.
|
||||
proxy = "http://www.python.org"
|
||||
|
||||
# Urls we exclude (ie, allow IIS to handle itself) - all are lowered,
|
||||
# and these entries exist by default on Vista...
|
||||
excludes = ["/iisstart.htm", "/welcome.png"]
|
||||
|
||||
# An "io completion" function, called when ecb.ExecURL completes...
|
||||
def io_callback(ecb, url, cbIO, errcode):
|
||||
# Get the status of our ExecURL
|
||||
httpstatus, substatus, win32 = ecb.GetExecURLStatus()
|
||||
print("ExecURL of %r finished with http status %d.%d, win32 status %d (%s)" % (
|
||||
url, httpstatus, substatus, win32, win32api.FormatMessage(win32).strip()))
|
||||
# nothing more to do!
|
||||
ecb.DoneWithSession()
|
||||
|
||||
# The ISAPI extension - handles all requests in the site.
|
||||
class Extension(threaded_extension.ThreadPoolExtension):
|
||||
"Python sample Extension"
|
||||
def Dispatch(self, ecb):
|
||||
# Note that our ThreadPoolExtension base class will catch exceptions
|
||||
# in our Dispatch method, and write the traceback to the client.
|
||||
# That is perfect for this sample, so we don't catch our own.
|
||||
#print 'IIS dispatching "%s"' % (ecb.GetServerVariable("URL"),)
|
||||
url = ecb.GetServerVariable("URL").decode("ascii")
|
||||
for exclude in excludes:
|
||||
if url.lower().startswith(exclude):
|
||||
print("excluding %s" % url)
|
||||
if ecb.Version < 0x60000:
|
||||
print("(but this is IIS5 or earlier - can't do 'excludes')")
|
||||
else:
|
||||
ecb.IOCompletion(io_callback, url)
|
||||
ecb.ExecURL(None, None, None, None, None, isapicon.HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR)
|
||||
return isapicon.HSE_STATUS_PENDING
|
||||
|
||||
new_url = proxy + url
|
||||
print("Opening %s" % new_url)
|
||||
fp = urlopen(new_url)
|
||||
headers = fp.info()
|
||||
# subtle py3k breakage: in py3k, str(headers) has normalized \r\n
|
||||
# back to \n and also stuck an extra \n term. py2k leaves the
|
||||
# \r\n from the server in tact and finishes with a single term.
|
||||
if sys.version_info < (3,0):
|
||||
header_text = str(headers) + "\r\n"
|
||||
else:
|
||||
# take *all* trailing \n off, replace remaining with
|
||||
# \r\n, then add the 2 trailing \r\n.
|
||||
header_text = str(headers).rstrip('\n').replace('\n', '\r\n') + '\r\n\r\n'
|
||||
ecb.SendResponseHeaders("200 OK", header_text, False)
|
||||
ecb.WriteClient(fp.read())
|
||||
ecb.DoneWithSession()
|
||||
print("Returned data from '%s'" % (new_url,))
|
||||
return isapicon.HSE_STATUS_SUCCESS
|
||||
|
||||
# The entry points for the ISAPI extension.
|
||||
def __ExtensionFactory__():
|
||||
return Extension()
|
||||
|
||||
if __name__=='__main__':
|
||||
# If run from the command-line, install ourselves.
|
||||
from isapi.install import *
|
||||
params = ISAPIParameters()
|
||||
# Setup the virtual directories - this is a list of directories our
|
||||
# extension uses - in this case only 1.
|
||||
# Each extension has a "script map" - this is the mapping of ISAPI
|
||||
# extensions.
|
||||
sm = [
|
||||
ScriptMapParams(Extension="*", Flags=0)
|
||||
]
|
||||
vd = VirtualDirParameters(Name="/",
|
||||
Description = Extension.__doc__,
|
||||
ScriptMaps = sm,
|
||||
ScriptMapUpdate = "replace"
|
||||
)
|
||||
params.VirtualDirs = [vd]
|
||||
HandleCommandLine(params)
|
|
@ -1,78 +0,0 @@
|
|||
# This is a sample ISAPI extension written in Python.
|
||||
|
||||
# This is like the other 'redirector' samples, but uses asnch IO when writing
|
||||
# back to the client (it does *not* use asynch io talking to the remote
|
||||
# server!)
|
||||
|
||||
from isapi import isapicon, threaded_extension
|
||||
import sys
|
||||
import traceback
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
|
||||
# sys.isapidllhandle will exist when we are loaded by the IIS framework.
|
||||
# In this case we redirect our output to the win32traceutil collector.
|
||||
if hasattr(sys, "isapidllhandle"):
|
||||
import win32traceutil
|
||||
|
||||
# The site we are proxying.
|
||||
proxy = "http://www.python.org"
|
||||
|
||||
# We synchronously read chunks of this size then asynchronously write them.
|
||||
CHUNK_SIZE=8192
|
||||
|
||||
# The callback made when IIS completes the asynch write.
|
||||
def io_callback(ecb, fp, cbIO, errcode):
|
||||
print("IO callback", ecb, fp, cbIO, errcode)
|
||||
chunk = fp.read(CHUNK_SIZE)
|
||||
if chunk:
|
||||
ecb.WriteClient(chunk, isapicon.HSE_IO_ASYNC)
|
||||
# and wait for the next callback to say this chunk is done.
|
||||
else:
|
||||
# eof - say we are complete.
|
||||
fp.close()
|
||||
ecb.DoneWithSession()
|
||||
|
||||
# The ISAPI extension - handles all requests in the site.
|
||||
class Extension(threaded_extension.ThreadPoolExtension):
|
||||
"Python sample proxy server - asynch version."
|
||||
def Dispatch(self, ecb):
|
||||
print('IIS dispatching "%s"' % (ecb.GetServerVariable("URL"),))
|
||||
url = ecb.GetServerVariable("URL")
|
||||
|
||||
new_url = proxy + url
|
||||
print("Opening %s" % new_url)
|
||||
fp = urllib.request.urlopen(new_url)
|
||||
headers = fp.info()
|
||||
ecb.SendResponseHeaders("200 OK", str(headers) + "\r\n", False)
|
||||
# now send the first chunk asynchronously
|
||||
ecb.ReqIOCompletion(io_callback, fp)
|
||||
chunk = fp.read(CHUNK_SIZE)
|
||||
if chunk:
|
||||
ecb.WriteClient(chunk, isapicon.HSE_IO_ASYNC)
|
||||
return isapicon.HSE_STATUS_PENDING
|
||||
# no data - just close things now.
|
||||
ecb.DoneWithSession()
|
||||
return isapicon.HSE_STATUS_SUCCESS
|
||||
|
||||
# The entry points for the ISAPI extension.
|
||||
def __ExtensionFactory__():
|
||||
return Extension()
|
||||
|
||||
if __name__=='__main__':
|
||||
# If run from the command-line, install ourselves.
|
||||
from isapi.install import *
|
||||
params = ISAPIParameters()
|
||||
# Setup the virtual directories - this is a list of directories our
|
||||
# extension uses - in this case only 1.
|
||||
# Each extension has a "script map" - this is the mapping of ISAPI
|
||||
# extensions.
|
||||
sm = [
|
||||
ScriptMapParams(Extension="*", Flags=0)
|
||||
]
|
||||
vd = VirtualDirParameters(Name="/",
|
||||
Description = Extension.__doc__,
|
||||
ScriptMaps = sm,
|
||||
ScriptMapUpdate = "replace"
|
||||
)
|
||||
params.VirtualDirs = [vd]
|
||||
HandleCommandLine(params)
|
|
@ -1,155 +0,0 @@
|
|||
# This is a sample configuration file for an ISAPI filter and extension
|
||||
# written in Python.
|
||||
#
|
||||
# Please see README.txt in this directory, and specifically the
|
||||
# information about the "loader" DLL - installing this sample will create
|
||||
# "_redirector_with_filter.dll" in the current directory. The readme explains
|
||||
# this.
|
||||
|
||||
# Executing this script (or any server config script) will install the extension
|
||||
# into your web server. As the server executes, the PyISAPI framework will load
|
||||
# this module and create your Extension and Filter objects.
|
||||
|
||||
# This sample provides sample redirector:
|
||||
# It is implemented by a filter and an extension, so that some requests can
|
||||
# be ignored. Compare with 'redirector_simple' which avoids the filter, but
|
||||
# is unable to selectively ignore certain requests.
|
||||
# The process is sample uses is:
|
||||
# * The filter is installed globally, as all filters are.
|
||||
# * A Virtual Directory named "python" is setup. This dir has our ISAPI
|
||||
# extension as the only application, mapped to file-extension '*'. Thus, our
|
||||
# extension handles *all* requests in this directory.
|
||||
# The basic process is that the filter does URL rewriting, redirecting every
|
||||
# URL to our Virtual Directory. Our extension then handles this request,
|
||||
# forwarding the data from the proxied site.
|
||||
# For example:
|
||||
# * URL of "index.html" comes in.
|
||||
# * Filter rewrites this to "/python/index.html"
|
||||
# * Our extension sees the full "/python/index.html", removes the leading
|
||||
# portion, and opens and forwards the remote URL.
|
||||
|
||||
|
||||
# This sample is very small - it avoid most error handling, etc. It is for
|
||||
# demonstration purposes only.
|
||||
|
||||
from isapi import isapicon, threaded_extension
|
||||
from isapi.simple import SimpleFilter
|
||||
import sys
|
||||
import traceback
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
|
||||
# sys.isapidllhandle will exist when we are loaded by the IIS framework.
|
||||
# In this case we redirect our output to the win32traceutil collector.
|
||||
if hasattr(sys, "isapidllhandle"):
|
||||
import win32traceutil
|
||||
|
||||
# The site we are proxying.
|
||||
proxy = "http://www.python.org"
|
||||
# The name of the virtual directory we install in, and redirect from.
|
||||
virtualdir = "/python"
|
||||
|
||||
# The key feature of this redirector over the simple redirector is that it
|
||||
# can choose to ignore certain responses by having the filter not rewrite them
|
||||
# to our virtual dir. For this sample, we just exclude the IIS help directory.
|
||||
|
||||
# The ISAPI extension - handles requests in our virtual dir, and sends the
|
||||
# response to the client.
|
||||
class Extension(threaded_extension.ThreadPoolExtension):
|
||||
"Python sample Extension"
|
||||
def Dispatch(self, ecb):
|
||||
# Note that our ThreadPoolExtension base class will catch exceptions
|
||||
# in our Dispatch method, and write the traceback to the client.
|
||||
# That is perfect for this sample, so we don't catch our own.
|
||||
#print 'IIS dispatching "%s"' % (ecb.GetServerVariable("URL"),)
|
||||
url = ecb.GetServerVariable("URL")
|
||||
if url.startswith(virtualdir):
|
||||
new_url = proxy + url[len(virtualdir):]
|
||||
print("Opening", new_url)
|
||||
fp = urllib.request.urlopen(new_url)
|
||||
headers = fp.info()
|
||||
ecb.SendResponseHeaders("200 OK", str(headers) + "\r\n", False)
|
||||
ecb.WriteClient(fp.read())
|
||||
ecb.DoneWithSession()
|
||||
print("Returned data from '%s'!" % (new_url,))
|
||||
else:
|
||||
# this should never happen - we should only see requests that
|
||||
# start with our virtual directory name.
|
||||
print("Not proxying '%s'" % (url,))
|
||||
|
||||
|
||||
# The ISAPI filter.
|
||||
class Filter(SimpleFilter):
|
||||
"Sample Python Redirector"
|
||||
filter_flags = isapicon.SF_NOTIFY_PREPROC_HEADERS | \
|
||||
isapicon.SF_NOTIFY_ORDER_DEFAULT
|
||||
|
||||
def HttpFilterProc(self, fc):
|
||||
#print "Filter Dispatch"
|
||||
nt = fc.NotificationType
|
||||
if nt != isapicon.SF_NOTIFY_PREPROC_HEADERS:
|
||||
return isapicon.SF_STATUS_REQ_NEXT_NOTIFICATION
|
||||
|
||||
pp = fc.GetData()
|
||||
url = pp.GetHeader("url")
|
||||
#print "URL is '%s'" % (url,)
|
||||
prefix = virtualdir
|
||||
if not url.startswith(prefix):
|
||||
new_url = prefix + url
|
||||
print("New proxied URL is '%s'" % (new_url,))
|
||||
pp.SetHeader("url", new_url)
|
||||
# For the sake of demonstration, show how the FilterContext
|
||||
# attribute is used. It always starts out life as None, and
|
||||
# any assignments made are automatically decref'd by the
|
||||
# framework during a SF_NOTIFY_END_OF_NET_SESSION notification.
|
||||
if fc.FilterContext is None:
|
||||
fc.FilterContext = 0
|
||||
fc.FilterContext += 1
|
||||
print("This is request number %d on this connection" % fc.FilterContext)
|
||||
return isapicon.SF_STATUS_REQ_HANDLED_NOTIFICATION
|
||||
else:
|
||||
print("Filter ignoring URL '%s'" % (url,))
|
||||
|
||||
# Some older code that handled SF_NOTIFY_URL_MAP.
|
||||
#~ print "Have URL_MAP notify"
|
||||
#~ urlmap = fc.GetData()
|
||||
#~ print "URI is", urlmap.URL
|
||||
#~ print "Path is", urlmap.PhysicalPath
|
||||
#~ if urlmap.URL.startswith("/UC/"):
|
||||
#~ # Find the /UC/ in the physical path, and nuke it (except
|
||||
#~ # as the path is physical, it is \)
|
||||
#~ p = urlmap.PhysicalPath
|
||||
#~ pos = p.index("\\UC\\")
|
||||
#~ p = p[:pos] + p[pos+3:]
|
||||
#~ p = r"E:\src\pyisapi\webroot\PyTest\formTest.htm"
|
||||
#~ print "New path is", p
|
||||
#~ urlmap.PhysicalPath = p
|
||||
|
||||
# The entry points for the ISAPI extension.
|
||||
def __FilterFactory__():
|
||||
return Filter()
|
||||
def __ExtensionFactory__():
|
||||
return Extension()
|
||||
|
||||
if __name__=='__main__':
|
||||
# If run from the command-line, install ourselves.
|
||||
from isapi.install import *
|
||||
params = ISAPIParameters()
|
||||
# Setup all filters - these are global to the site.
|
||||
params.Filters = [
|
||||
FilterParameters(Name="PythonRedirector",
|
||||
Description=Filter.__doc__),
|
||||
]
|
||||
# Setup the virtual directories - this is a list of directories our
|
||||
# extension uses - in this case only 1.
|
||||
# Each extension has a "script map" - this is the mapping of ISAPI
|
||||
# extensions.
|
||||
sm = [
|
||||
ScriptMapParams(Extension="*", Flags=0)
|
||||
]
|
||||
vd = VirtualDirParameters(Name=virtualdir[1:],
|
||||
Description = Extension.__doc__,
|
||||
ScriptMaps = sm,
|
||||
ScriptMapUpdate = "replace"
|
||||
)
|
||||
params.VirtualDirs = [vd]
|
||||
HandleCommandLine(params)
|
|
@ -1,154 +0,0 @@
|
|||
# This extension is used mainly for testing purposes - it is not
|
||||
# designed to be a simple sample, but instead is a hotch-potch of things
|
||||
# that attempts to exercise the framework.
|
||||
|
||||
from isapi import isapicon
|
||||
from isapi.simple import SimpleExtension
|
||||
import sys, os, stat
|
||||
|
||||
if hasattr(sys, "isapidllhandle"):
|
||||
import win32traceutil
|
||||
|
||||
# We use the same reload support as 'advanced.py' demonstrates.
|
||||
from isapi import InternalReloadException
|
||||
import win32event, win32file, winerror, win32con, threading
|
||||
|
||||
# A watcher thread that checks for __file__ changing.
|
||||
# When it detects it, it simply sets "change_detected" to true.
|
||||
class ReloadWatcherThread(threading.Thread):
|
||||
def __init__(self):
|
||||
self.change_detected = False
|
||||
self.filename = __file__
|
||||
if self.filename.endswith("c") or self.filename.endswith("o"):
|
||||
self.filename = self.filename[:-1]
|
||||
self.handle = win32file.FindFirstChangeNotification(
|
||||
os.path.dirname(self.filename),
|
||||
False, # watch tree?
|
||||
win32con.FILE_NOTIFY_CHANGE_LAST_WRITE)
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
last_time = os.stat(self.filename)[stat.ST_MTIME]
|
||||
while 1:
|
||||
try:
|
||||
rc = win32event.WaitForSingleObject(self.handle,
|
||||
win32event.INFINITE)
|
||||
win32file.FindNextChangeNotification(self.handle)
|
||||
except win32event.error as details:
|
||||
# handle closed - thread should terminate.
|
||||
if details.winerror != winerror.ERROR_INVALID_HANDLE:
|
||||
raise
|
||||
break
|
||||
this_time = os.stat(self.filename)[stat.ST_MTIME]
|
||||
if this_time != last_time:
|
||||
print("Detected file change - flagging for reload.")
|
||||
self.change_detected = True
|
||||
last_time = this_time
|
||||
|
||||
def stop(self):
|
||||
win32file.FindCloseChangeNotification(self.handle)
|
||||
|
||||
def TransmitFileCallback(ecb, hFile, cbIO, errCode):
|
||||
print("Transmit complete!")
|
||||
ecb.close()
|
||||
|
||||
# The ISAPI extension - handles requests in our virtual dir, and sends the
|
||||
# response to the client.
|
||||
class Extension(SimpleExtension):
|
||||
"Python test Extension"
|
||||
def __init__(self):
|
||||
self.reload_watcher = ReloadWatcherThread()
|
||||
self.reload_watcher.start()
|
||||
|
||||
def HttpExtensionProc(self, ecb):
|
||||
# NOTE: If you use a ThreadPoolExtension, you must still perform
|
||||
# this check in HttpExtensionProc - raising the exception from
|
||||
# The "Dispatch" method will just cause the exception to be
|
||||
# rendered to the browser.
|
||||
if self.reload_watcher.change_detected:
|
||||
print("Doing reload")
|
||||
raise InternalReloadException
|
||||
|
||||
if ecb.GetServerVariable("UNICODE_URL").endswith("test.py"):
|
||||
file_flags = win32con.FILE_FLAG_SEQUENTIAL_SCAN | win32con.FILE_FLAG_OVERLAPPED
|
||||
hfile = win32file.CreateFile(__file__, win32con.GENERIC_READ,
|
||||
0, None, win32con.OPEN_EXISTING,
|
||||
file_flags, None)
|
||||
flags = isapicon.HSE_IO_ASYNC | isapicon.HSE_IO_DISCONNECT_AFTER_SEND | \
|
||||
isapicon.HSE_IO_SEND_HEADERS
|
||||
# We pass hFile to the callback simply as a way of keeping it alive
|
||||
# for the duration of the transmission
|
||||
try:
|
||||
ecb.TransmitFile(TransmitFileCallback, hfile,
|
||||
int(hfile),
|
||||
"200 OK",
|
||||
0, 0, None, None, flags)
|
||||
except:
|
||||
# Errors keep this source file open!
|
||||
hfile.Close()
|
||||
raise
|
||||
else:
|
||||
# default response
|
||||
ecb.SendResponseHeaders("200 OK", "Content-Type: text/html\r\n\r\n", 0)
|
||||
print("<HTML><BODY>", file=ecb)
|
||||
print("The root of this site is at", ecb.MapURLToPath("/"), file=ecb)
|
||||
print("</BODY></HTML>", file=ecb)
|
||||
ecb.close()
|
||||
return isapicon.HSE_STATUS_SUCCESS
|
||||
|
||||
def TerminateExtension(self, status):
|
||||
self.reload_watcher.stop()
|
||||
|
||||
# The entry points for the ISAPI extension.
|
||||
def __ExtensionFactory__():
|
||||
return Extension()
|
||||
|
||||
# Our special command line customization.
|
||||
# Pre-install hook for our virtual directory.
|
||||
def PreInstallDirectory(params, options):
|
||||
# If the user used our special '--description' option,
|
||||
# then we override our default.
|
||||
if options.description:
|
||||
params.Description = options.description
|
||||
|
||||
# Post install hook for our entire script
|
||||
def PostInstall(params, options):
|
||||
print()
|
||||
print("The sample has been installed.")
|
||||
print("Point your browser to /PyISAPITest")
|
||||
|
||||
# Handler for our custom 'status' argument.
|
||||
def status_handler(options, log, arg):
|
||||
"Query the status of something"
|
||||
print("Everything seems to be fine!")
|
||||
|
||||
custom_arg_handlers = {"status": status_handler}
|
||||
|
||||
if __name__=='__main__':
|
||||
# If run from the command-line, install ourselves.
|
||||
from isapi.install import *
|
||||
params = ISAPIParameters(PostInstall = PostInstall)
|
||||
# Setup the virtual directories - this is a list of directories our
|
||||
# extension uses - in this case only 1.
|
||||
# Each extension has a "script map" - this is the mapping of ISAPI
|
||||
# extensions.
|
||||
sm = [
|
||||
ScriptMapParams(Extension="*", Flags=0)
|
||||
]
|
||||
vd = VirtualDirParameters(Name="PyISAPITest",
|
||||
Description = Extension.__doc__,
|
||||
ScriptMaps = sm,
|
||||
ScriptMapUpdate = "replace",
|
||||
# specify the pre-install hook.
|
||||
PreInstall = PreInstallDirectory
|
||||
)
|
||||
params.VirtualDirs = [vd]
|
||||
# Setup our custom option parser.
|
||||
from optparse import OptionParser
|
||||
parser = OptionParser('') # blank usage, so isapi sets it.
|
||||
parser.add_option("", "--description",
|
||||
action="store",
|
||||
help="custom description to use for the virtual directory")
|
||||
|
||||
HandleCommandLine(params, opt_parser=parser,
|
||||
custom_arg_handlers = custom_arg_handlers)
|
|
@ -1,68 +0,0 @@
|
|||
"""Simple base-classes for extensions and filters.
|
||||
|
||||
None of the filter and extension functions are considered 'optional' by the
|
||||
framework. These base-classes provide simple implementations for the
|
||||
Initialize and Terminate functions, allowing you to omit them,
|
||||
|
||||
It is not necessary to use these base-classes - but if you don't, you
|
||||
must ensure each of the required methods are implemented.
|
||||
"""
|
||||
|
||||
class SimpleExtension:
|
||||
"Base class for a simple ISAPI extension"
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def GetExtensionVersion(self, vi):
|
||||
"""Called by the ISAPI framework to get the extension version
|
||||
|
||||
The default implementation uses the classes docstring to
|
||||
set the extension description."""
|
||||
# nod to our reload capability - vi is None when we are reloaded.
|
||||
if vi is not None:
|
||||
vi.ExtensionDesc = self.__doc__
|
||||
|
||||
def HttpExtensionProc(self, control_block):
|
||||
"""Called by the ISAPI framework for each extension request.
|
||||
|
||||
sub-classes must provide an implementation for this method.
|
||||
"""
|
||||
raise NotImplementedError("sub-classes should override HttpExtensionProc")
|
||||
|
||||
def TerminateExtension(self, status):
|
||||
"""Called by the ISAPI framework as the extension terminates.
|
||||
"""
|
||||
pass
|
||||
|
||||
class SimpleFilter:
|
||||
"Base class for a a simple ISAPI filter"
|
||||
filter_flags = None
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def GetFilterVersion(self, fv):
|
||||
"""Called by the ISAPI framework to get the extension version
|
||||
|
||||
The default implementation uses the classes docstring to
|
||||
set the extension description, and uses the classes
|
||||
filter_flags attribute to set the ISAPI filter flags - you
|
||||
must specify filter_flags in your class.
|
||||
"""
|
||||
if self.filter_flags is None:
|
||||
raise RuntimeError("You must specify the filter flags")
|
||||
# nod to our reload capability - fv is None when we are reloaded.
|
||||
if fv is not None:
|
||||
fv.Flags = self.filter_flags
|
||||
fv.FilterDesc = self.__doc__
|
||||
|
||||
def HttpFilterProc(self, fc):
|
||||
"""Called by the ISAPI framework for each filter request.
|
||||
|
||||
sub-classes must provide an implementation for this method.
|
||||
"""
|
||||
raise NotImplementedError("sub-classes should override HttpExtensionProc")
|
||||
|
||||
def TerminateFilter(self, status):
|
||||
"""Called by the ISAPI framework as the filter terminates.
|
||||
"""
|
||||
pass
|
|
@ -1,3 +0,0 @@
|
|||
This is a directory for tests of the PyISAPI framework.
|
||||
|
||||
For demos, please see the pyisapi 'samples' directory.
|
|
@ -1,111 +0,0 @@
|
|||
# This is an ISAPI extension purely for testing purposes. It is NOT
|
||||
# a 'demo' (even though it may be useful!)
|
||||
#
|
||||
# Install this extension, then point your browser to:
|
||||
# "http://localhost/pyisapi_test/test1"
|
||||
# This will execute the method 'test1' below. See below for the list of
|
||||
# test methods that are acceptable.
|
||||
|
||||
from isapi import isapicon, threaded_extension, ExtensionError
|
||||
from isapi.simple import SimpleFilter
|
||||
import traceback
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
import winerror
|
||||
|
||||
# If we have no console (eg, am running from inside IIS), redirect output
|
||||
# somewhere useful - in this case, the standard win32 trace collector.
|
||||
import win32api
|
||||
try:
|
||||
win32api.GetConsoleTitle()
|
||||
except win32api.error:
|
||||
# No console - redirect
|
||||
import win32traceutil
|
||||
|
||||
# The ISAPI extension - handles requests in our virtual dir, and sends the
|
||||
# response to the client.
|
||||
class Extension(threaded_extension.ThreadPoolExtension):
|
||||
"Python ISAPI Tester"
|
||||
def Dispatch(self, ecb):
|
||||
print('Tester dispatching "%s"' % (ecb.GetServerVariable("URL"),))
|
||||
url = ecb.GetServerVariable("URL")
|
||||
test_name = url.split("/")[-1]
|
||||
meth = getattr(self, test_name, None)
|
||||
if meth is None:
|
||||
raise AttributeError("No test named '%s'" % (test_name,))
|
||||
result = meth(ecb)
|
||||
if result is None:
|
||||
# This means the test finalized everything
|
||||
return
|
||||
ecb.SendResponseHeaders("200 OK", "Content-type: text/html\r\n\r\n",
|
||||
False)
|
||||
print("<HTML><BODY>Finished running test <i>", test_name, "</i>", file=ecb)
|
||||
print("<pre>", file=ecb)
|
||||
print(result, file=ecb)
|
||||
print("</pre>", file=ecb)
|
||||
print("</BODY></HTML>", file=ecb)
|
||||
ecb.DoneWithSession()
|
||||
|
||||
def test1(self, ecb):
|
||||
try:
|
||||
ecb.GetServerVariable("foo bar")
|
||||
raise RuntimeError("should have failed!")
|
||||
except ExtensionError as err:
|
||||
assert err.errno == winerror.ERROR_INVALID_INDEX, err
|
||||
return "worked!"
|
||||
|
||||
def test_long_vars(self, ecb):
|
||||
qs = ecb.GetServerVariable("QUERY_STRING")
|
||||
# Our implementation has a default buffer size of 8k - so we test
|
||||
# the code that handles an overflow by ensuring there are more
|
||||
# than 8k worth of chars in the URL.
|
||||
expected_query = ('x' * 8500)
|
||||
if len(qs)==0:
|
||||
# Just the URL with no query part - redirect to myself, but with
|
||||
# a huge query portion.
|
||||
me = ecb.GetServerVariable("URL")
|
||||
headers = "Location: " + me + "?" + expected_query + "\r\n\r\n"
|
||||
ecb.SendResponseHeaders("301 Moved", headers)
|
||||
ecb.DoneWithSession()
|
||||
return None
|
||||
if qs == expected_query:
|
||||
return "Total length of variable is %d - test worked!" % (len(qs),)
|
||||
else:
|
||||
return "Unexpected query portion! Got %d chars, expected %d" % \
|
||||
(len(qs), len(expected_query))
|
||||
|
||||
def test_unicode_vars(self, ecb):
|
||||
# We need to check that we are running IIS6! This seems the only
|
||||
# effective way from an extension.
|
||||
ver = float(ecb.GetServerVariable("SERVER_SOFTWARE").split('/')[1])
|
||||
if ver < 6.0:
|
||||
return "This is IIS version %g - unicode only works in IIS6 and later" % ver
|
||||
|
||||
us = ecb.GetServerVariable("UNICODE_SERVER_NAME")
|
||||
if not isinstance(us, str):
|
||||
raise RuntimeError("unexpected type!")
|
||||
if us != str(ecb.GetServerVariable("SERVER_NAME")):
|
||||
raise RuntimeError("Unicode and non-unicode values were not the same")
|
||||
return "worked!"
|
||||
|
||||
# The entry points for the ISAPI extension.
|
||||
def __ExtensionFactory__():
|
||||
return Extension()
|
||||
|
||||
if __name__=='__main__':
|
||||
# If run from the command-line, install ourselves.
|
||||
from isapi.install import *
|
||||
params = ISAPIParameters()
|
||||
# Setup the virtual directories - this is a list of directories our
|
||||
# extension uses - in this case only 1.
|
||||
# Each extension has a "script map" - this is the mapping of ISAPI
|
||||
# extensions.
|
||||
sm = [
|
||||
ScriptMapParams(Extension="*", Flags=0)
|
||||
]
|
||||
vd = VirtualDirParameters(Name="pyisapi_test",
|
||||
Description = Extension.__doc__,
|
||||
ScriptMaps = sm,
|
||||
ScriptMapUpdate = "replace"
|
||||
)
|
||||
params.VirtualDirs = [vd]
|
||||
HandleCommandLine(params)
|
|
@ -1,171 +0,0 @@
|
|||
"""An ISAPI extension base class implemented using a thread-pool."""
|
||||
# $Id$
|
||||
|
||||
import sys
|
||||
import time
|
||||
from isapi import isapicon, ExtensionError
|
||||
import isapi.simple
|
||||
from win32file import GetQueuedCompletionStatus, CreateIoCompletionPort, \
|
||||
PostQueuedCompletionStatus, CloseHandle
|
||||
from win32security import SetThreadToken
|
||||
from win32event import INFINITE
|
||||
from pywintypes import OVERLAPPED
|
||||
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
ISAPI_REQUEST = 1
|
||||
ISAPI_SHUTDOWN = 2
|
||||
|
||||
class WorkerThread(threading.Thread):
|
||||
def __init__(self, extension, io_req_port):
|
||||
self.running = False
|
||||
self.io_req_port = io_req_port
|
||||
self.extension = extension
|
||||
threading.Thread.__init__(self)
|
||||
# We wait 15 seconds for a thread to terminate, but if it fails to,
|
||||
# we don't want the process to hang at exit waiting for it...
|
||||
self.setDaemon(True)
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
while self.running:
|
||||
errCode, bytes, key, overlapped = \
|
||||
GetQueuedCompletionStatus(self.io_req_port, INFINITE)
|
||||
if key == ISAPI_SHUTDOWN and overlapped is None:
|
||||
break
|
||||
|
||||
# Let the parent extension handle the command.
|
||||
dispatcher = self.extension.dispatch_map.get(key)
|
||||
if dispatcher is None:
|
||||
raise RuntimeError("Bad request '%s'" % (key,))
|
||||
|
||||
dispatcher(errCode, bytes, key, overlapped)
|
||||
|
||||
def call_handler(self, cblock):
|
||||
self.extension.Dispatch(cblock)
|
||||
|
||||
# A generic thread-pool based extension, using IO Completion Ports.
|
||||
# Sub-classes can override one method to implement a simple extension, or
|
||||
# may leverage the CompletionPort to queue their own requests, and implement a
|
||||
# fully asynch extension.
|
||||
class ThreadPoolExtension(isapi.simple.SimpleExtension):
|
||||
"Base class for an ISAPI extension based around a thread-pool"
|
||||
max_workers = 20
|
||||
worker_shutdown_wait = 15000 # 15 seconds for workers to quit...
|
||||
def __init__(self):
|
||||
self.workers = []
|
||||
# extensible dispatch map, for sub-classes that need to post their
|
||||
# own requests to the completion port.
|
||||
# Each of these functions is called with the result of
|
||||
# GetQueuedCompletionStatus for our port.
|
||||
self.dispatch_map = {
|
||||
ISAPI_REQUEST: self.DispatchConnection,
|
||||
}
|
||||
|
||||
def GetExtensionVersion(self, vi):
|
||||
isapi.simple.SimpleExtension.GetExtensionVersion(self, vi)
|
||||
# As per Q192800, the CompletionPort should be created with the number
|
||||
# of processors, even if the number of worker threads is much larger.
|
||||
# Passing 0 means the system picks the number.
|
||||
self.io_req_port = CreateIoCompletionPort(-1, None, 0, 0)
|
||||
# start up the workers
|
||||
self.workers = []
|
||||
for i in range(self.max_workers):
|
||||
worker = WorkerThread(self, self.io_req_port)
|
||||
worker.start()
|
||||
self.workers.append(worker)
|
||||
|
||||
def HttpExtensionProc(self, control_block):
|
||||
overlapped = OVERLAPPED()
|
||||
overlapped.object = control_block
|
||||
PostQueuedCompletionStatus(self.io_req_port, 0, ISAPI_REQUEST, overlapped)
|
||||
return isapicon.HSE_STATUS_PENDING
|
||||
|
||||
def TerminateExtension(self, status):
|
||||
for worker in self.workers:
|
||||
worker.running = False
|
||||
for worker in self.workers:
|
||||
PostQueuedCompletionStatus(self.io_req_port, 0, ISAPI_SHUTDOWN, None)
|
||||
# wait for them to terminate - pity we aren't using 'native' threads
|
||||
# as then we could do a smart wait - but now we need to poll....
|
||||
end_time = time.time() + self.worker_shutdown_wait/1000
|
||||
alive = self.workers
|
||||
while alive:
|
||||
if time.time() > end_time:
|
||||
# xxx - might be nice to log something here.
|
||||
break
|
||||
time.sleep(0.2)
|
||||
alive = [w for w in alive if w.isAlive()]
|
||||
self.dispatch_map = {} # break circles
|
||||
CloseHandle(self.io_req_port)
|
||||
|
||||
# This is the one operation the base class supports - a simple
|
||||
# Connection request. We setup the thread-token, and dispatch to the
|
||||
# sub-class's 'Dispatch' method.
|
||||
def DispatchConnection(self, errCode, bytes, key, overlapped):
|
||||
control_block = overlapped.object
|
||||
# setup the correct user for this request
|
||||
hRequestToken = control_block.GetImpersonationToken()
|
||||
SetThreadToken(None, hRequestToken)
|
||||
try:
|
||||
try:
|
||||
self.Dispatch(control_block)
|
||||
except:
|
||||
self.HandleDispatchError(control_block)
|
||||
finally:
|
||||
# reset the security context
|
||||
SetThreadToken(None, None)
|
||||
|
||||
def Dispatch(self, ecb):
|
||||
"""Overridden by the sub-class to handle connection requests.
|
||||
|
||||
This class creates a thread-pool using a Windows completion port,
|
||||
and dispatches requests via this port. Sub-classes can generally
|
||||
implement each connection request using blocking reads and writes, and
|
||||
the thread-pool will still provide decent response to the end user.
|
||||
|
||||
The sub-class can set a max_workers attribute (default is 20). Note
|
||||
that this generally does *not* mean 20 threads will all be concurrently
|
||||
running, via the magic of Windows completion ports.
|
||||
|
||||
There is no default implementation - sub-classes must implement this.
|
||||
"""
|
||||
raise NotImplementedError("sub-classes should override Dispatch")
|
||||
|
||||
def HandleDispatchError(self, ecb):
|
||||
"""Handles errors in the Dispatch method.
|
||||
|
||||
When a Dispatch method call fails, this method is called to handle
|
||||
the exception. The default implementation formats the traceback
|
||||
in the browser.
|
||||
"""
|
||||
ecb.HttpStatusCode = isapicon.HSE_STATUS_ERROR
|
||||
#control_block.LogData = "we failed!"
|
||||
exc_typ, exc_val, exc_tb = sys.exc_info()
|
||||
limit = None
|
||||
try:
|
||||
try:
|
||||
import cgi
|
||||
ecb.SendResponseHeaders("200 OK", "Content-type: text/html\r\n\r\n",
|
||||
False)
|
||||
print(file=ecb)
|
||||
print("<H3>Traceback (most recent call last):</H3>", file=ecb)
|
||||
list = traceback.format_tb(exc_tb, limit) + \
|
||||
traceback.format_exception_only(exc_typ, exc_val)
|
||||
print("<PRE>%s<B>%s</B></PRE>" % (
|
||||
cgi.escape("".join(list[:-1])), cgi.escape(list[-1]),), file=ecb)
|
||||
except ExtensionError:
|
||||
# The client disconnected without reading the error body -
|
||||
# its probably not a real browser at the other end, ignore it.
|
||||
pass
|
||||
except:
|
||||
print("FAILED to render the error message!")
|
||||
traceback.print_exc()
|
||||
print("ORIGINAL extension error:")
|
||||
traceback.print_exception(exc_typ, exc_val, exc_tb)
|
||||
finally:
|
||||
# holding tracebacks in a local of a frame that may itself be
|
||||
# part of a traceback used to be evil and cause leaks!
|
||||
exc_tb = None
|
||||
ecb.DoneWithSession()
|
|
@ -1,3 +0,0 @@
|
|||
# Magic utility that "redirects" to pythoncomxx.dll
|
||||
import pywintypes
|
||||
pywintypes.__import_pywin32_system_module__("pythoncom", globals())
|
Binary file not shown.
Binary file not shown.
|
@ -1,30 +0,0 @@
|
|||
Unless stated in the specfic source file, this work is
|
||||
Copyright (c) 1994-2008, Mark Hammond
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither name of Mark Hammond nor the name of contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Binary file not shown.
Binary file not shown.
|
@ -1,221 +0,0 @@
|
|||
# basictimerapp - a really simple timer application.
|
||||
# This should be run using the command line:
|
||||
# pythonwin /app demos\basictimerapp.py
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import sys
|
||||
from pywin.framework import app, cmdline, dlgappcore, cmdline
|
||||
import timer
|
||||
import time
|
||||
import string
|
||||
|
||||
class TimerAppDialog(dlgappcore.AppDialog):
|
||||
softspace=1
|
||||
def __init__(self, appName = ""):
|
||||
dlgappcore.AppDialog.__init__(self, win32ui.IDD_GENERAL_STATUS)
|
||||
self.timerAppName = appName
|
||||
self.argOff = 0
|
||||
if len(self.timerAppName)==0:
|
||||
if len(sys.argv)>1 and sys.argv[1][0]!='/':
|
||||
self.timerAppName = sys.argv[1]
|
||||
self.argOff = 1
|
||||
|
||||
def PreDoModal(self):
|
||||
# sys.stderr = sys.stdout
|
||||
pass
|
||||
|
||||
def ProcessArgs(self, args):
|
||||
for arg in args:
|
||||
if arg=="/now":
|
||||
self.OnOK()
|
||||
|
||||
def OnInitDialog(self):
|
||||
win32ui.SetProfileFileName('pytimer.ini')
|
||||
self.title = win32ui.GetProfileVal(self.timerAppName, "Title", "Remote System Timer")
|
||||
self.buildTimer = win32ui.GetProfileVal(self.timerAppName, "Timer", "EachMinuteIntervaler()")
|
||||
self.doWork = win32ui.GetProfileVal(self.timerAppName, "Work", "DoDemoWork()")
|
||||
# replace "\n" with real \n.
|
||||
self.doWork = self.doWork.replace('\\n','\n')
|
||||
dlgappcore.AppDialog.OnInitDialog(self)
|
||||
|
||||
self.SetWindowText(self.title)
|
||||
self.prompt1 = self.GetDlgItem(win32ui.IDC_PROMPT1)
|
||||
self.prompt2 = self.GetDlgItem(win32ui.IDC_PROMPT2)
|
||||
self.prompt3 = self.GetDlgItem(win32ui.IDC_PROMPT3)
|
||||
self.butOK = self.GetDlgItem(win32con.IDOK)
|
||||
self.butCancel = self.GetDlgItem(win32con.IDCANCEL)
|
||||
self.prompt1.SetWindowText("Python Timer App")
|
||||
self.prompt2.SetWindowText("")
|
||||
self.prompt3.SetWindowText("")
|
||||
self.butOK.SetWindowText("Do it now")
|
||||
self.butCancel.SetWindowText("Close")
|
||||
|
||||
self.timerManager = TimerManager(self)
|
||||
self.ProcessArgs(sys.argv[self.argOff:])
|
||||
self.timerManager.go()
|
||||
return 1
|
||||
|
||||
def OnDestroy(self,msg):
|
||||
dlgappcore.AppDialog.OnDestroy(self, msg)
|
||||
self.timerManager.stop()
|
||||
def OnOK(self):
|
||||
# stop the timer, then restart after setting special boolean
|
||||
self.timerManager.stop()
|
||||
self.timerManager.bConnectNow = 1
|
||||
self.timerManager.go()
|
||||
return
|
||||
# def OnCancel(self): default behaviour - cancel == close.
|
||||
# return
|
||||
|
||||
class TimerManager:
|
||||
def __init__(self, dlg):
|
||||
self.dlg = dlg
|
||||
self.timerId = None
|
||||
self.intervaler = eval(self.dlg.buildTimer)
|
||||
self.bConnectNow = 0
|
||||
self.bHaveSetPrompt1 = 0
|
||||
def CaptureOutput(self):
|
||||
self.oldOut = sys.stdout
|
||||
self.oldErr = sys.stderr
|
||||
sys.stdout = sys.stderr = self
|
||||
self.bHaveSetPrompt1 = 0
|
||||
def ReleaseOutput(self):
|
||||
sys.stdout = self.oldOut
|
||||
sys.stderr = self.oldErr
|
||||
def write(self, str):
|
||||
s = str.strip()
|
||||
if len(s):
|
||||
if self.bHaveSetPrompt1:
|
||||
dest = self.dlg.prompt3
|
||||
else:
|
||||
dest = self.dlg.prompt1
|
||||
self.bHaveSetPrompt1 = 1
|
||||
dest.SetWindowText(s)
|
||||
def go(self):
|
||||
self.OnTimer(None,None)
|
||||
def stop(self):
|
||||
if self.timerId: timer.kill_timer (self.timerId)
|
||||
self.timerId = None
|
||||
|
||||
def OnTimer(self, id, timeVal):
|
||||
if id: timer.kill_timer (id)
|
||||
if self.intervaler.IsTime() or self.bConnectNow :
|
||||
# do the work.
|
||||
try:
|
||||
self.dlg.SetWindowText(self.dlg.title + " - Working...")
|
||||
self.dlg.butOK.EnableWindow(0)
|
||||
self.dlg.butCancel.EnableWindow(0)
|
||||
self.CaptureOutput()
|
||||
try:
|
||||
exec(self.dlg.doWork)
|
||||
print("The last operation completed successfully.")
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
str = "Failed: %s: %s" % (t, repr(v))
|
||||
print(str)
|
||||
self.oldErr.write(str)
|
||||
tb = None # Prevent cycle
|
||||
finally:
|
||||
self.ReleaseOutput()
|
||||
self.dlg.butOK.EnableWindow()
|
||||
self.dlg.butCancel.EnableWindow()
|
||||
self.dlg.SetWindowText(self.dlg.title)
|
||||
else:
|
||||
now = time.time()
|
||||
nextTime = self.intervaler.GetNextTime()
|
||||
if nextTime:
|
||||
timeDiffSeconds = nextTime - now
|
||||
timeDiffMinutes = int(timeDiffSeconds / 60)
|
||||
timeDiffSeconds = timeDiffSeconds % 60
|
||||
timeDiffHours = int(timeDiffMinutes / 60)
|
||||
timeDiffMinutes = timeDiffMinutes % 60
|
||||
self.dlg.prompt1.SetWindowText("Next connection due in %02d:%02d:%02d" % (timeDiffHours,timeDiffMinutes,timeDiffSeconds))
|
||||
self.timerId = timer.set_timer (self.intervaler.GetWakeupInterval(), self.OnTimer)
|
||||
self.bConnectNow = 0
|
||||
|
||||
class TimerIntervaler:
|
||||
def __init__(self):
|
||||
self.nextTime = None
|
||||
self.wakeUpInterval = 2000
|
||||
def GetWakeupInterval(self):
|
||||
return self.wakeUpInterval
|
||||
def GetNextTime(self):
|
||||
return self.nextTime
|
||||
def IsTime(self):
|
||||
now = time.time()
|
||||
if self.nextTime is None:
|
||||
self.nextTime = self.SetFirstTime(now)
|
||||
ret = 0
|
||||
if now >= self.nextTime:
|
||||
ret = 1
|
||||
self.nextTime = self.SetNextTime(self.nextTime, now)
|
||||
# do the work.
|
||||
return ret
|
||||
|
||||
class EachAnyIntervaler(TimerIntervaler):
|
||||
def __init__(self, timeAt, timePos, timeAdd, wakeUpInterval = None):
|
||||
TimerIntervaler.__init__(self)
|
||||
self.timeAt = timeAt
|
||||
self.timePos = timePos
|
||||
self.timeAdd = timeAdd
|
||||
if wakeUpInterval:
|
||||
self.wakeUpInterval = wakeUpInterval
|
||||
def SetFirstTime(self, now):
|
||||
timeTup = time.localtime(now)
|
||||
lst = []
|
||||
for item in timeTup:
|
||||
lst.append(item)
|
||||
bAdd = timeTup[self.timePos] > self.timeAt
|
||||
lst[self.timePos] = self.timeAt
|
||||
for pos in range(self.timePos+1, 6):
|
||||
lst[pos]=0
|
||||
ret = time.mktime(tuple(lst))
|
||||
if (bAdd):
|
||||
ret = ret + self.timeAdd
|
||||
return ret;
|
||||
|
||||
def SetNextTime(self, lastTime, now):
|
||||
return lastTime + self.timeAdd
|
||||
|
||||
class EachMinuteIntervaler(EachAnyIntervaler):
|
||||
def __init__(self, at=0):
|
||||
EachAnyIntervaler.__init__(self, at, 5, 60, 2000)
|
||||
|
||||
class EachHourIntervaler(EachAnyIntervaler):
|
||||
def __init__(self, at=0):
|
||||
EachAnyIntervaler.__init__(self, at, 4, 3600, 10000)
|
||||
|
||||
class EachDayIntervaler(EachAnyIntervaler):
|
||||
def __init__(self,at=0):
|
||||
EachAnyIntervaler.__init__(self, at, 3, 86400, 10000)
|
||||
|
||||
class TimerDialogApp(dlgappcore.DialogApp):
|
||||
def CreateDialog(self):
|
||||
return TimerAppDialog()
|
||||
|
||||
def DoDemoWork():
|
||||
print("Doing the work...")
|
||||
print("About to connect")
|
||||
win32api.MessageBeep(win32con.MB_ICONASTERISK)
|
||||
win32api.Sleep(2000)
|
||||
print("Doing something else...")
|
||||
win32api.MessageBeep(win32con.MB_ICONEXCLAMATION)
|
||||
win32api.Sleep(2000)
|
||||
print("More work.")
|
||||
win32api.MessageBeep(win32con.MB_ICONHAND)
|
||||
win32api.Sleep(2000)
|
||||
print("The last bit.")
|
||||
win32api.MessageBeep(win32con.MB_OK)
|
||||
win32api.Sleep(2000)
|
||||
|
||||
app = TimerDialogApp()
|
||||
|
||||
def t():
|
||||
t = TimerAppDialog("Test Dialog")
|
||||
t.DoModal()
|
||||
return t
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NeedApp()
|
|
@ -1,194 +0,0 @@
|
|||
# A demo of an Application object that has some custom print functionality.
|
||||
|
||||
# If you desire, you can also run this from inside Pythonwin, in which
|
||||
# case it will do the demo inside the Pythonwin environment.
|
||||
|
||||
# This sample was contributed by Roger Burnham.
|
||||
|
||||
from pywin.mfc import docview, dialog, afxres
|
||||
from pywin.framework import app
|
||||
|
||||
import win32con
|
||||
import win32ui
|
||||
import win32api
|
||||
|
||||
PRINTDLGORD = 1538
|
||||
IDC_PRINT_MAG_EDIT = 1010
|
||||
|
||||
|
||||
class PrintDemoTemplate(docview.DocTemplate):
|
||||
def _SetupSharedMenu_(self):
|
||||
pass
|
||||
|
||||
class PrintDemoView(docview.ScrollView):
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
ret = self._obj_.OnInitialUpdate()
|
||||
self.colors = {'Black' : (0x00<<0) + (0x00<<8) + (0x00<<16),
|
||||
'Red' : (0xff<<0) + (0x00<<8) + (0x00<<16),
|
||||
'Green' : (0x00<<0) + (0xff<<8) + (0x00<<16),
|
||||
'Blue' : (0x00<<0) + (0x00<<8) + (0xff<<16),
|
||||
'Cyan' : (0x00<<0) + (0xff<<8) + (0xff<<16),
|
||||
'Magenta': (0xff<<0) + (0x00<<8) + (0xff<<16),
|
||||
'Yellow' : (0xff<<0) + (0xff<<8) + (0x00<<16),
|
||||
}
|
||||
self.pens = {}
|
||||
for name, color in self.colors.items():
|
||||
self.pens[name] = win32ui.CreatePen(win32con.PS_SOLID,
|
||||
5, color)
|
||||
self.pen = None
|
||||
self.size = (128,128)
|
||||
self.SetScaleToFitSize(self.size)
|
||||
self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT)
|
||||
self.HookCommand(self.OnFilePrintPreview,
|
||||
win32ui.ID_FILE_PRINT_PREVIEW)
|
||||
return ret
|
||||
|
||||
def OnDraw(self, dc):
|
||||
oldPen = None
|
||||
x,y = self.size
|
||||
delta = 2
|
||||
colors = list(self.colors.keys())
|
||||
colors.sort()
|
||||
colors = colors*2
|
||||
for color in colors:
|
||||
if oldPen is None:
|
||||
oldPen = dc.SelectObject(self.pens[color])
|
||||
else:
|
||||
dc.SelectObject(self.pens[color])
|
||||
dc.MoveTo(( delta, delta))
|
||||
dc.LineTo((x-delta, delta))
|
||||
dc.LineTo((x-delta, y-delta))
|
||||
dc.LineTo(( delta, y-delta))
|
||||
dc.LineTo(( delta, delta))
|
||||
delta = delta + 4
|
||||
if x-delta <= 0 or y-delta <= 0:
|
||||
break
|
||||
dc.SelectObject(oldPen)
|
||||
|
||||
def OnPrepareDC (self, dc, pInfo):
|
||||
if dc.IsPrinting():
|
||||
mag = self.prtDlg['mag']
|
||||
dc.SetMapMode(win32con.MM_ANISOTROPIC);
|
||||
dc.SetWindowOrg((0, 0))
|
||||
dc.SetWindowExt((1, 1))
|
||||
dc.SetViewportOrg((0, 0))
|
||||
dc.SetViewportExt((mag, mag))
|
||||
|
||||
def OnPreparePrinting(self, pInfo):
|
||||
flags = (win32ui.PD_USEDEVMODECOPIES|
|
||||
win32ui.PD_PAGENUMS|
|
||||
win32ui.PD_NOPAGENUMS|
|
||||
win32ui.PD_NOSELECTION)
|
||||
self.prtDlg = ImagePrintDialog(pInfo, PRINTDLGORD, flags)
|
||||
pInfo.SetPrintDialog(self.prtDlg)
|
||||
pInfo.SetMinPage(1)
|
||||
pInfo.SetMaxPage(1)
|
||||
pInfo.SetFromPage(1)
|
||||
pInfo.SetToPage(1)
|
||||
ret = self.DoPreparePrinting(pInfo)
|
||||
return ret
|
||||
|
||||
def OnBeginPrinting(self, dc, pInfo):
|
||||
return self._obj_.OnBeginPrinting(dc, pInfo)
|
||||
|
||||
def OnEndPrinting(self, dc, pInfo):
|
||||
del self.prtDlg
|
||||
return self._obj_.OnEndPrinting(dc, pInfo)
|
||||
|
||||
def OnFilePrintPreview(self, *arg):
|
||||
self._obj_.OnFilePrintPreview()
|
||||
|
||||
def OnFilePrint(self, *arg):
|
||||
self._obj_.OnFilePrint()
|
||||
|
||||
def OnPrint(self, dc, pInfo):
|
||||
doc = self.GetDocument()
|
||||
metrics = dc.GetTextMetrics()
|
||||
cxChar = metrics['tmAveCharWidth']
|
||||
cyChar = metrics['tmHeight']
|
||||
left, top, right, bottom = pInfo.GetDraw()
|
||||
dc.TextOut(0, 2*cyChar, doc.GetTitle())
|
||||
top = top + (7*cyChar)/2
|
||||
dc.MoveTo(left, top)
|
||||
dc.LineTo(right, top)
|
||||
top = top + cyChar
|
||||
# this seems to have not effect...
|
||||
# get what I want with the dc.SetWindowOrg calls
|
||||
pInfo.SetDraw((left, top, right, bottom))
|
||||
dc.SetWindowOrg((0, -top))
|
||||
|
||||
self.OnDraw(dc)
|
||||
dc.SetTextAlign(win32con.TA_LEFT|win32con.TA_BOTTOM)
|
||||
|
||||
rect = self.GetWindowRect()
|
||||
rect = self.ScreenToClient(rect)
|
||||
height = (rect[3]-rect[1])
|
||||
dc.SetWindowOrg((0, -(top+height+cyChar)))
|
||||
dc.MoveTo(left, 0)
|
||||
dc.LineTo(right, 0)
|
||||
|
||||
x = 0
|
||||
y = (3*cyChar)/2
|
||||
|
||||
dc.TextOut(x, y, doc.GetTitle())
|
||||
y = y + cyChar
|
||||
|
||||
|
||||
class PrintDemoApp(app.CApp):
|
||||
def __init__(self):
|
||||
app.CApp.__init__(self)
|
||||
|
||||
def InitInstance(self):
|
||||
template = PrintDemoTemplate(None, None,
|
||||
None, PrintDemoView)
|
||||
self.AddDocTemplate(template)
|
||||
self._obj_.InitMDIInstance()
|
||||
self.LoadMainFrame()
|
||||
doc = template.OpenDocumentFile(None)
|
||||
doc.SetTitle('Custom Print Document')
|
||||
|
||||
|
||||
class ImagePrintDialog(dialog.PrintDialog):
|
||||
|
||||
sectionPos = 'Image Print Demo'
|
||||
|
||||
def __init__(self, pInfo, dlgID, flags=win32ui.PD_USEDEVMODECOPIES):
|
||||
dialog.PrintDialog.__init__(self, pInfo, dlgID, flags=flags)
|
||||
mag = win32ui.GetProfileVal(self.sectionPos,
|
||||
'Document Magnification',
|
||||
0)
|
||||
if mag <= 0:
|
||||
mag = 2
|
||||
win32ui.WriteProfileVal(self.sectionPos,
|
||||
'Document Magnification',
|
||||
mag)
|
||||
|
||||
self['mag'] = mag
|
||||
|
||||
def OnInitDialog(self):
|
||||
self.magCtl = self.GetDlgItem(IDC_PRINT_MAG_EDIT)
|
||||
self.magCtl.SetWindowText(repr(self['mag']))
|
||||
return dialog.PrintDialog.OnInitDialog(self)
|
||||
def OnOK(self):
|
||||
dialog.PrintDialog.OnOK(self)
|
||||
strMag = self.magCtl.GetWindowText()
|
||||
try:
|
||||
self['mag'] = int(strMag)
|
||||
except:
|
||||
pass
|
||||
win32ui.WriteProfileVal(self.sectionPos,
|
||||
'Document Magnification',
|
||||
self['mag'])
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
# Running under Pythonwin
|
||||
def test():
|
||||
template = PrintDemoTemplate(None, None,
|
||||
None, PrintDemoView)
|
||||
template.OpenDocumentFile(None)
|
||||
test()
|
||||
else:
|
||||
app = PrintDemoApp()
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
# Utilities for the demos
|
||||
|
||||
import sys, win32api, win32con, win32ui
|
||||
|
||||
NotScriptMsg = """\
|
||||
This demo program is not designed to be run as a Script, but is
|
||||
probably used by some other test program. Please try another demo.
|
||||
"""
|
||||
|
||||
NeedGUIMsg = """\
|
||||
This demo program can only be run from inside of Pythonwin
|
||||
|
||||
You must start Pythonwin, and select 'Run' from the toolbar or File menu
|
||||
"""
|
||||
|
||||
|
||||
NeedAppMsg = """\
|
||||
This demo program is a 'Pythonwin Application'.
|
||||
|
||||
It is more demo code than an example of Pythonwin's capabilities.
|
||||
|
||||
To run it, you must execute the command:
|
||||
pythonwin.exe /app "%s"
|
||||
|
||||
Would you like to execute it now?
|
||||
"""
|
||||
|
||||
def NotAScript():
|
||||
import win32ui
|
||||
win32ui.MessageBox(NotScriptMsg, "Demos")
|
||||
|
||||
def NeedGoodGUI():
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
rc = HaveGoodGUI()
|
||||
if not rc:
|
||||
win32ui.MessageBox(NeedGUIMsg, "Demos")
|
||||
return rc
|
||||
|
||||
def NeedApp():
|
||||
import win32ui
|
||||
rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO)
|
||||
if rc==win32con.IDYES:
|
||||
try:
|
||||
parent = win32ui.GetMainFrame().GetSafeHwnd()
|
||||
win32api.ShellExecute(parent, None, 'pythonwin.exe', '/app "%s"' % sys.argv[0], None, 1)
|
||||
except win32api.error as details:
|
||||
win32ui.MessageBox("Error executing command - %s" % (details), "Demos")
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
|
@ -1,46 +0,0 @@
|
|||
# dlgappdemo - a demo of a dialog application.
|
||||
# This is a demonstration of both a custom "application" module,
|
||||
# and a Python program in a dialog box.
|
||||
#
|
||||
# NOTE: You CAN NOT import this module from either PythonWin or Python.
|
||||
# This module must be specified on the commandline to PythonWin only.
|
||||
# eg, PythonWin /app dlgappdemo.py
|
||||
|
||||
from pywin.framework import dlgappcore, app
|
||||
import win32ui
|
||||
import sys
|
||||
|
||||
class TestDialogApp(dlgappcore.DialogApp):
|
||||
def CreateDialog(self):
|
||||
return TestAppDialog()
|
||||
|
||||
|
||||
class TestAppDialog(dlgappcore.AppDialog):
|
||||
def __init__(self):
|
||||
self.edit = None
|
||||
dlgappcore.AppDialog.__init__(self, win32ui.IDD_LARGE_EDIT)
|
||||
def OnInitDialog(self):
|
||||
self.SetWindowText('Test dialog application')
|
||||
self.edit = self.GetDlgItem(win32ui.IDC_EDIT1)
|
||||
print("Hello from Python")
|
||||
print("args are:", end=' ')
|
||||
for arg in sys.argv:
|
||||
print(arg)
|
||||
return 1
|
||||
|
||||
def PreDoModal(self):
|
||||
sys.stdout = sys.stderr = self
|
||||
|
||||
def write(self, str):
|
||||
if self.edit:
|
||||
self.edit.SetSel(-2)
|
||||
# translate \n to \n\r
|
||||
self.edit.ReplaceSel(str.replace('\n','\r\n'))
|
||||
else:
|
||||
win32ui.OutputDebug("dlgapp - no edit control! >>\n%s\n<<\n" % str )
|
||||
|
||||
app.AppBuilder = TestDialogApp
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NeedApp()
|
|
@ -1,62 +0,0 @@
|
|||
# dojobapp - do a job, show the result in a dialog, and exit.
|
||||
#
|
||||
# Very simple - faily minimal dialog based app.
|
||||
#
|
||||
# This should be run using the command line:
|
||||
# pythonwin /app demos\dojobapp.py
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import sys
|
||||
from pywin.framework import app, dlgappcore
|
||||
import string
|
||||
|
||||
class DoJobAppDialog(dlgappcore.AppDialog):
|
||||
softspace=1
|
||||
def __init__(self, appName = ""):
|
||||
self.appName = appName
|
||||
dlgappcore.AppDialog.__init__(self, win32ui.IDD_GENERAL_STATUS)
|
||||
|
||||
def PreDoModal(self):
|
||||
pass
|
||||
|
||||
def ProcessArgs(self, args):
|
||||
pass
|
||||
|
||||
def OnInitDialog(self):
|
||||
self.SetWindowText(self.appName)
|
||||
butCancel = self.GetDlgItem(win32con.IDCANCEL)
|
||||
butCancel.ShowWindow(win32con.SW_HIDE)
|
||||
p1 = self.GetDlgItem(win32ui.IDC_PROMPT1)
|
||||
p2 = self.GetDlgItem(win32ui.IDC_PROMPT2)
|
||||
|
||||
# Do something here!
|
||||
|
||||
p1.SetWindowText("Hello there")
|
||||
p2.SetWindowText("from the demo")
|
||||
def OnDestroy(self,msg):
|
||||
pass
|
||||
# def OnOK(self):
|
||||
# pass
|
||||
# def OnCancel(self): default behaviour - cancel == close.
|
||||
# return
|
||||
|
||||
class DoJobDialogApp(dlgappcore.DialogApp):
|
||||
def CreateDialog(self):
|
||||
return DoJobAppDialog("Do Something")
|
||||
|
||||
class CopyToDialogApp(DoJobDialogApp):
|
||||
def __init__(self):
|
||||
DoJobDialogApp.__init__(self)
|
||||
|
||||
app.AppBuilder = DoJobDialogApp
|
||||
|
||||
def t():
|
||||
t = DoJobAppDialog("Copy To")
|
||||
t.DoModal()
|
||||
return t
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NeedApp()
|
|
@ -1,45 +0,0 @@
|
|||
##
|
||||
## helloapp.py
|
||||
##
|
||||
##
|
||||
## A nice, small 'hello world' Pythonwin application.
|
||||
## NOT an MDI application - just a single, normal, top-level window.
|
||||
##
|
||||
## MUST be run with the command line "pythonwin.exe /app helloapp.py"
|
||||
## (or if you are really keen, rename "pythonwin.exe" to something else, then
|
||||
## using MSVC or similar, edit the string section in the .EXE to name this file)
|
||||
##
|
||||
## Originally by Willy Heineman <wheineman@uconect.net>
|
||||
|
||||
|
||||
import win32con
|
||||
import win32ui
|
||||
from pywin.mfc import window, dialog, afxres
|
||||
from pywin.mfc.thread import WinApp
|
||||
|
||||
# The main frame.
|
||||
# Does almost nothing at all - doesnt even create a child window!
|
||||
class HelloWindow(window.Wnd):
|
||||
def __init__(self):
|
||||
# The window.Wnd ctor creates a Window object, and places it in
|
||||
# self._obj_. Note the window object exists, but the window itself
|
||||
# does not!
|
||||
window.Wnd.__init__(self, win32ui.CreateWnd())
|
||||
|
||||
# Now we ask the window object to create the window itself.
|
||||
self._obj_.CreateWindowEx(win32con.WS_EX_CLIENTEDGE, \
|
||||
win32ui.RegisterWndClass(0, 0, win32con.COLOR_WINDOW + 1), \
|
||||
'Hello World!', win32con.WS_OVERLAPPEDWINDOW, \
|
||||
(100, 100, 400, 300), None, 0, None)
|
||||
|
||||
# The application object itself.
|
||||
class HelloApp(WinApp):
|
||||
|
||||
def InitInstance(self):
|
||||
self.frame = HelloWindow()
|
||||
self.frame.ShowWindow(win32con.SW_SHOWNORMAL)
|
||||
# We need to tell MFC what our main frame is.
|
||||
self.SetMainFrame(self.frame)
|
||||
|
||||
# Now create the application object itself!
|
||||
app = HelloApp()
|
|
@ -1,108 +0,0 @@
|
|||
# cmdserver.py
|
||||
|
||||
# Demo code that is not Pythonwin related, but too good to throw away...
|
||||
|
||||
import win32api
|
||||
import sys
|
||||
from pywin.framework import winout
|
||||
|
||||
import _thread, sys
|
||||
|
||||
import traceback
|
||||
|
||||
class ThreadWriter:
|
||||
"Assign an instance to sys.stdout for per-thread printing objects - Courtesy Guido!"
|
||||
def __init__(self):
|
||||
"Constructor -- initialize the table of writers"
|
||||
self.writers = {}
|
||||
self.origStdOut = None
|
||||
def register(self, writer):
|
||||
"Register the writer for the current thread"
|
||||
self.writers[_thread.get_ident()] = writer
|
||||
if self.origStdOut is None:
|
||||
self.origStdOut = sys.stdout
|
||||
sys.stdout = self
|
||||
|
||||
def unregister(self):
|
||||
"Remove the writer for the current thread, if any"
|
||||
try:
|
||||
del self.writers[_thread.get_ident()]
|
||||
except KeyError:
|
||||
pass
|
||||
if len(self.writers)==0:
|
||||
sys.stdout = self.origStdOut
|
||||
self.origStdOut = None
|
||||
|
||||
def getwriter(self):
|
||||
"Return the current thread's writer, default sys.stdout"
|
||||
try:
|
||||
return self.writers[_thread.get_ident()]
|
||||
except KeyError:
|
||||
return self.origStdOut
|
||||
|
||||
def write(self, str):
|
||||
"Write to the current thread's writer, default sys.stdout"
|
||||
self.getwriter().write(str)
|
||||
|
||||
def Test():
|
||||
num=1
|
||||
while num<1000:
|
||||
print('Hello there no ' + str(num))
|
||||
win32api.Sleep(50)
|
||||
num = num + 1
|
||||
|
||||
class flags:
|
||||
SERVER_BEST = 0
|
||||
SERVER_IMMEDIATE = 1
|
||||
SERVER_THREAD = 2
|
||||
SERVER_PROCESS = 3
|
||||
|
||||
def StartServer( cmd, title=None, bCloseOnEnd=0, serverFlags = flags.SERVER_BEST ):
|
||||
out = winout.WindowOutput( title, None, winout.flags.WQ_IDLE )
|
||||
if not title:
|
||||
title=cmd
|
||||
out.Create(title)
|
||||
# ServerThread((out, cmd, title, bCloseOnEnd))
|
||||
# out = sys.stdout
|
||||
_thread.start_new_thread( ServerThread, (out, cmd, title, bCloseOnEnd) )
|
||||
|
||||
def ServerThread(myout, cmd, title, bCloseOnEnd):
|
||||
try:
|
||||
writer.register(myout)
|
||||
print('Executing "%s"\n' % cmd)
|
||||
bOK = 1
|
||||
try:
|
||||
import __main__
|
||||
exec (cmd+'\n', __main__.__dict__)
|
||||
except:
|
||||
bOK = 0
|
||||
if bOK:
|
||||
print("Command terminated without errors.")
|
||||
else:
|
||||
t, v, tb = sys.exc_info()
|
||||
print(t, ': ', v)
|
||||
traceback.print_tb(tb)
|
||||
tb = None # prevent a cycle
|
||||
print("Command terminated with an unhandled exception")
|
||||
writer.unregister()
|
||||
if bOK and bCloseOnEnd:
|
||||
myout.frame.DestroyWindow()
|
||||
|
||||
# Unhandled exception of any kind in a thread kills the gui!
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
print(t, ': ', v)
|
||||
traceback.print_tb(tb)
|
||||
tb = None
|
||||
print("Thread failed")
|
||||
|
||||
# assist for reloading (when debugging) - use only 1 tracer object,
|
||||
# else a large chain of tracer objects will exist.
|
||||
#try:
|
||||
# writer
|
||||
#except NameError:
|
||||
# writer=ThreadWriter()
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
#
|
||||
# Window creation example
|
||||
#
|
||||
# This example creates a minimal "control" that just fills in its
|
||||
# window with red. To make your own control, subclass Control and
|
||||
# write your own OnPaint() method. See PyCWnd.HookMessage for what
|
||||
# the parameters to OnPaint are.
|
||||
#
|
||||
|
||||
from pywin.mfc import dialog, window
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
|
||||
class Control(window.Wnd):
|
||||
"""Generic control class"""
|
||||
def __init__ (self):
|
||||
window.Wnd.__init__(self, win32ui.CreateWnd ())
|
||||
|
||||
def OnPaint (self):
|
||||
dc, paintStruct = self.BeginPaint()
|
||||
self.DoPaint(dc)
|
||||
self.EndPaint(paintStruct)
|
||||
|
||||
def DoPaint (self, dc): # Override this!
|
||||
pass
|
||||
|
||||
class RedBox (Control):
|
||||
def DoPaint (self, dc):
|
||||
dc.FillSolidRect (self.GetClientRect(), win32api.RGB(255,0,0))
|
||||
|
||||
|
||||
class RedBoxWithPie (RedBox):
|
||||
def DoPaint (self, dc):
|
||||
RedBox.DoPaint(self, dc)
|
||||
r = self.GetClientRect()
|
||||
dc.Pie(r[0], r[1], r[2], r[3], 0,0,r[2], r[3]//2)
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = (win32con.DS_MODALFRAME |
|
||||
win32con.WS_POPUP |
|
||||
win32con.WS_VISIBLE |
|
||||
win32con.WS_CAPTION |
|
||||
win32con.WS_SYSMENU |
|
||||
win32con.DS_SETFONT)
|
||||
cs = (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE)
|
||||
|
||||
w = 64
|
||||
h = 64
|
||||
|
||||
dlg = [["Red box",
|
||||
(0, 0, w, h),
|
||||
style,
|
||||
None,
|
||||
(8, "MS Sans Serif")],
|
||||
]
|
||||
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
|
||||
dlg.append([128,
|
||||
"Cancel",
|
||||
win32con.IDCANCEL,
|
||||
(7, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON])
|
||||
|
||||
return dlg
|
||||
|
||||
class TestDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.redbox = RedBox ()
|
||||
self.redbox.CreateWindow (None, "RedBox",
|
||||
win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE,
|
||||
(5, 5, 90, 68),
|
||||
self, 1003)
|
||||
return rc
|
||||
|
||||
class TestPieDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.control = RedBoxWithPie()
|
||||
self.control.CreateWindow (None, "RedBox with Pie",
|
||||
win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE,
|
||||
(5, 5, 90, 68),
|
||||
self, 1003)
|
||||
|
||||
def demo(modal=0):
|
||||
d = TestPieDialog (MakeDlgTemplate())
|
||||
if modal:
|
||||
d.DoModal()
|
||||
else:
|
||||
d.CreateWindow()
|
||||
|
||||
if __name__=='__main__':
|
||||
demo(1)
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
# Utilities for the demos
|
||||
|
||||
import sys, win32api, win32con, win32ui
|
||||
|
||||
NotScriptMsg = """\
|
||||
This demo program is not designed to be run as a Script, but is
|
||||
probably used by some other test program. Please try another demo.
|
||||
"""
|
||||
|
||||
NeedGUIMsg = """\
|
||||
This demo program can only be run from inside of Pythonwin
|
||||
|
||||
You must start Pythonwin, and select 'Run' from the toolbar or File menu
|
||||
"""
|
||||
|
||||
|
||||
NeedAppMsg = """\
|
||||
This demo program is a 'Pythonwin Application'.
|
||||
|
||||
It is more demo code than an example of Pythonwin's capabilities.
|
||||
|
||||
To run it, you must execute the command:
|
||||
pythonwin.exe /app "%s"
|
||||
|
||||
Would you like to execute it now?
|
||||
"""
|
||||
|
||||
def NotAScript():
|
||||
import win32ui
|
||||
win32ui.MessageBox(NotScriptMsg, "Demos")
|
||||
|
||||
def NeedGoodGUI():
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
rc = HaveGoodGUI()
|
||||
if not rc:
|
||||
win32ui.MessageBox(NeedGUIMsg, "Demos")
|
||||
return rc
|
||||
|
||||
def NeedApp():
|
||||
import win32ui
|
||||
rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO)
|
||||
if rc==win32con.IDYES:
|
||||
try:
|
||||
parent = win32ui.GetMainFrame().GetSafeHwnd()
|
||||
win32api.ShellExecute(parent, None, 'pythonwin.exe', '/app "%s"' % sys.argv[0], None, 1)
|
||||
except win32api.error as details:
|
||||
win32ui.MessageBox("Error executing command - %s" % (details), "Demos")
|
||||
|
||||
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
|
@ -1,69 +0,0 @@
|
|||
# A demo which creates a view and a frame which displays a PPM format bitmap
|
||||
#
|
||||
# This hasnnt been run in a while, as I dont have many of that format around!
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import string
|
||||
|
||||
class DIBView:
|
||||
def __init__(self, doc, dib):
|
||||
self.dib = dib
|
||||
self.view = win32ui.CreateView(doc)
|
||||
self.width = self.height = 0
|
||||
# set up message handlers
|
||||
# self.view.OnPrepareDC = self.OnPrepareDC
|
||||
self.view.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
self.width = win32api.LOWORD(lParam)
|
||||
self.height = win32api.HIWORD(lParam)
|
||||
|
||||
def OnDraw (self, ob, dc):
|
||||
# set sizes used for "non strecth" mode.
|
||||
self.view.SetScrollSizes(win32con.MM_TEXT, self.dib.GetSize())
|
||||
dibSize = self.dib.GetSize()
|
||||
dibRect = (0,0,dibSize[0], dibSize[1])
|
||||
# stretch BMP.
|
||||
#self.dib.Paint(dc, (0,0,self.width, self.height),dibRect)
|
||||
# non stretch.
|
||||
self.dib.Paint(dc)
|
||||
|
||||
class DIBDemo:
|
||||
def __init__(self, filename, * bPBM):
|
||||
# init data members
|
||||
f = open(filename, 'rb')
|
||||
dib=win32ui.CreateDIBitmap()
|
||||
if len(bPBM)>0:
|
||||
magic=f.readline()
|
||||
if magic != "P6\n":
|
||||
print("The file is not a PBM format file")
|
||||
raise ValueError("Failed - The file is not a PBM format file")
|
||||
# check magic?
|
||||
rowcollist=f.readline().split()
|
||||
cols=int(rowcollist[0])
|
||||
rows=int(rowcollist[1])
|
||||
f.readline() # whats this one?
|
||||
dib.LoadPBMData(f,(cols,rows))
|
||||
else:
|
||||
dib.LoadWindowsFormatFile(f)
|
||||
f.close()
|
||||
# create doc/view
|
||||
self.doc = win32ui.CreateDoc()
|
||||
self.dibView = DIBView( self.doc, dib )
|
||||
self.frame = win32ui.CreateMDIFrame()
|
||||
self.frame.LoadFrame() # this will force OnCreateClient
|
||||
self.doc.SetTitle ('DIB Demo')
|
||||
self.frame.ShowWindow()
|
||||
|
||||
# display the sucka
|
||||
self.frame.ActivateFrame()
|
||||
|
||||
def OnCreateClient( self, createparams, context ):
|
||||
self.dibView.view.CreateWindow(self.frame)
|
||||
return 1
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
|
@ -1,137 +0,0 @@
|
|||
# A Demo of Pythonwin's Dialog and Property Page support.
|
||||
|
||||
###################
|
||||
#
|
||||
# First demo - use the built-in to Pythonwin "Tab Stop" dialog, but
|
||||
# customise it heavily.
|
||||
#
|
||||
# ID's for the tabstop dialog - out test.
|
||||
#
|
||||
from win32ui import IDD_SET_TABSTOPS
|
||||
from win32ui import IDC_EDIT_TABS
|
||||
from win32ui import IDC_PROMPT_TABS
|
||||
from win32con import IDOK
|
||||
from win32con import IDCANCEL
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
|
||||
from pywin.mfc import dialog
|
||||
|
||||
class TestDialog(dialog.Dialog):
|
||||
def __init__(self, modal=1):
|
||||
dialog.Dialog.__init__(self, IDD_SET_TABSTOPS)
|
||||
self.counter=0
|
||||
if modal:
|
||||
self.DoModal()
|
||||
else:
|
||||
self.CreateWindow()
|
||||
|
||||
def OnInitDialog(self):
|
||||
# Set the caption of the dialog itself.
|
||||
self.SetWindowText("Used to be Tab Stops!")
|
||||
# Get a child control, remember it, and change its text.
|
||||
self.edit=self.GetDlgItem(IDC_EDIT_TABS) # the text box.
|
||||
self.edit.SetWindowText("Test")
|
||||
# Hook a Windows message for the dialog.
|
||||
self.edit.HookMessage(self.KillFocus, win32con.WM_KILLFOCUS)
|
||||
# Get the prompt control, and change its next.
|
||||
prompt=self.GetDlgItem(IDC_PROMPT_TABS) # the prompt box.
|
||||
prompt.SetWindowText("Prompt")
|
||||
# And the same for the button..
|
||||
cancel=self.GetDlgItem(IDCANCEL) # the cancel button
|
||||
cancel.SetWindowText("&Kill me")
|
||||
|
||||
# And just for demonstration purposes, we hook the notify message for the dialog.
|
||||
# This allows us to be notified when the Edit Control text changes.
|
||||
self.HookCommand(self.OnNotify, IDC_EDIT_TABS)
|
||||
|
||||
def OnNotify(self, controlid, code):
|
||||
if code==win32con.EN_CHANGE:
|
||||
print("Edit text changed!")
|
||||
return 1 # I handled this, so no need to call defaults!
|
||||
|
||||
# kill focus for the edit box.
|
||||
# Simply increment the value in the text box.
|
||||
def KillFocus(self,msg):
|
||||
self.counter=self.counter+1
|
||||
if self.edit != None:
|
||||
self.edit.SetWindowText(str(self.counter))
|
||||
|
||||
# Called when the dialog box is terminating...
|
||||
def OnDestroy(self,msg):
|
||||
del self.edit
|
||||
del self.counter
|
||||
|
||||
# A very simply Property Sheet.
|
||||
# We only make a new class for demonstration purposes.
|
||||
class TestSheet(dialog.PropertySheet):
|
||||
def __init__(self, title):
|
||||
dialog.PropertySheet.__init__(self, title)
|
||||
self.HookMessage(self.OnActivate, win32con.WM_ACTIVATE)
|
||||
def OnActivate(self, msg):
|
||||
pass
|
||||
|
||||
# A very simply Property Page, which will be "owned" by the above
|
||||
# Property Sheet.
|
||||
# We create a new class, just so we can hook a control notification.
|
||||
class TestPage(dialog.PropertyPage):
|
||||
def OnInitDialog(self):
|
||||
# We use the HookNotify function to allow Python to respond to
|
||||
# Windows WM_NOTIFY messages.
|
||||
# In this case, we are interested in BN_CLICKED messages.
|
||||
self.HookNotify(self.OnNotify, win32con.BN_CLICKED)
|
||||
def OnNotify(self, std, extra):
|
||||
print("OnNotify", std, extra)
|
||||
|
||||
# Some code that actually uses these objects.
|
||||
def demo(modal = 0):
|
||||
TestDialog(modal)
|
||||
|
||||
# property sheet/page demo
|
||||
ps=win32ui.CreatePropertySheet('Property Sheet/Page Demo')
|
||||
# Create a completely standard PropertyPage.
|
||||
page1=win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO1)
|
||||
# Create our custom property page.
|
||||
page2=TestPage(win32ui.IDD_PROPDEMO2)
|
||||
ps.AddPage(page1)
|
||||
ps.AddPage(page2)
|
||||
if modal:
|
||||
ps.DoModal()
|
||||
else:
|
||||
style = win32con.WS_SYSMENU|win32con.WS_POPUP|win32con.WS_CAPTION|win32con.DS_MODALFRAME|win32con.WS_VISIBLE
|
||||
styleex = win32con.WS_EX_DLGMODALFRAME | win32con.WS_EX_PALETTEWINDOW
|
||||
ps.CreateWindow(win32ui.GetMainFrame(), style, styleex)
|
||||
|
||||
|
||||
def test(modal=1):
|
||||
|
||||
# dlg=dialog.Dialog(1010)
|
||||
# dlg.CreateWindow()
|
||||
# dlg.EndDialog(0)
|
||||
# del dlg
|
||||
# return
|
||||
# property sheet/page demo
|
||||
ps=TestSheet('Property Sheet/Page Demo')
|
||||
page1=win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO1)
|
||||
page2=win32ui.CreatePropertyPage(win32ui.IDD_PROPDEMO2)
|
||||
ps.AddPage(page1)
|
||||
ps.AddPage(page2)
|
||||
del page1
|
||||
del page2
|
||||
if modal:
|
||||
ps.DoModal()
|
||||
else:
|
||||
ps.CreateWindow(win32ui.GetMainFrame())
|
||||
return ps
|
||||
|
||||
def d():
|
||||
dlg = win32ui.CreateDialog(win32ui.IDD_DEBUGGER)
|
||||
dlg.datalist.append((win32ui.IDC_DBG_RADIOSTACK, "radio"))
|
||||
print("data list is ", dlg.datalist)
|
||||
dlg.data['radio']=1
|
||||
dlg.DoModal()
|
||||
print(dlg.data['radio'])
|
||||
|
||||
if __name__=='__main__':
|
||||
demo(1)
|
|
@ -1,73 +0,0 @@
|
|||
# dyndlg.py
|
||||
# contributed by Curt Hagenlocher <chi@earthlink.net>
|
||||
|
||||
# Dialog Template params:
|
||||
# Parameter 0 - Window caption
|
||||
# Parameter 1 - Bounds (rect tuple)
|
||||
# Parameter 2 - Window style
|
||||
# Parameter 3 - Extended style
|
||||
# Parameter 4 - Font tuple
|
||||
# Parameter 5 - Menu name
|
||||
# Parameter 6 - Window class
|
||||
# Dialog item params:
|
||||
# Parameter 0 - Window class
|
||||
# Parameter 1 - Text
|
||||
# Parameter 2 - ID
|
||||
# Parameter 3 - Bounds
|
||||
# Parameter 4 - Style
|
||||
# Parameter 5 - Extended style
|
||||
# Parameter 6 - Extra data
|
||||
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
from pywin.mfc import dialog, window
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
dlg = [ ["Select Warehouse", (0, 0, 177, 93), style, None, (8, "MS Sans Serif")], ]
|
||||
dlg.append([130, "Current Warehouse:", -1, (7, 7, 69, 9), cs | win32con.SS_LEFT])
|
||||
dlg.append([130, "ASTORIA", 128, (16, 17, 99, 7), cs | win32con.SS_LEFT])
|
||||
dlg.append([130, "New &Warehouse:", -1, (7, 29, 69, 9), cs | win32con.SS_LEFT])
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
# dlg.append([131, None, 130, (5, 40, 110, 48),
|
||||
# s | win32con.LBS_NOTIFY | win32con.LBS_SORT | win32con.LBS_NOINTEGRALHEIGHT | win32con.WS_VSCROLL | win32con.WS_BORDER])
|
||||
dlg.append(["{8E27C92B-1264-101C-8A2F-040224009C02}", None, 131, (5, 40, 110, 48),win32con.WS_TABSTOP])
|
||||
|
||||
dlg.append([128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
s = win32con.BS_PUSHBUTTON | s
|
||||
dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 22, 50, 14), s])
|
||||
dlg.append([128, "&Help", 100, (124, 74, 50, 14), s])
|
||||
|
||||
return dlg
|
||||
|
||||
def test1():
|
||||
win32ui.CreateDialogIndirect( MakeDlgTemplate() ).DoModal()
|
||||
|
||||
def test2():
|
||||
dialog.Dialog( MakeDlgTemplate() ).DoModal()
|
||||
|
||||
def test3():
|
||||
dlg = win32ui.LoadDialogResource(win32ui.IDD_SET_TABSTOPS)
|
||||
dlg[0][0] = 'New Dialog Title'
|
||||
dlg[0][1] = (80, 20, 161, 60)
|
||||
dlg[1][1] = '&Confusion:'
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_TABSTOP | win32con.BS_PUSHBUTTON
|
||||
dlg.append([128, "&Help", 100, (111, 41, 40, 14), cs])
|
||||
dialog.Dialog( dlg ).DoModal()
|
||||
|
||||
def test4():
|
||||
page1=dialog.PropertyPage(win32ui.LoadDialogResource(win32ui.IDD_PROPDEMO1))
|
||||
page2=dialog.PropertyPage(win32ui.LoadDialogResource(win32ui.IDD_PROPDEMO2))
|
||||
ps=dialog.PropertySheet('Property Sheet/Page Demo', None, [page1, page2])
|
||||
ps.DoModal()
|
||||
|
||||
def testall():
|
||||
test1()
|
||||
test2()
|
||||
test3()
|
||||
test4()
|
||||
|
||||
if __name__=='__main__':
|
||||
testall()
|
|
@ -1,79 +0,0 @@
|
|||
# Demo of Generic document windows, DC, and Font usage
|
||||
# by Dave Brennan (brennan@hal.com)
|
||||
|
||||
# usage examples:
|
||||
|
||||
# >>> from fontdemo import *
|
||||
# >>> d = FontDemo('Hello, Python')
|
||||
# >>> f1 = { 'name':'Arial', 'height':36, 'weight':win32con.FW_BOLD}
|
||||
# >>> d.SetFont(f1)
|
||||
# >>> f2 = {'name':'Courier New', 'height':24, 'italic':1}
|
||||
# >>> d.SetFont (f2)
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
|
||||
from pywin.mfc import docview
|
||||
|
||||
|
||||
# font is a dictionary in which the following elements matter:
|
||||
# (the best matching font to supplied parameters is returned)
|
||||
# name string name of the font as known by Windows
|
||||
# size point size of font in logical units
|
||||
# weight weight of font (win32con.FW_NORMAL, win32con.FW_BOLD)
|
||||
# italic boolean; true if set to anything but None
|
||||
# underline boolean; true if set to anything but None
|
||||
|
||||
class FontView(docview.ScrollView):
|
||||
def __init__(self, doc, text = 'Python Rules!', font_spec = {'name':'Arial', 'height':42}):
|
||||
docview.ScrollView.__init__(self, doc)
|
||||
self.font = win32ui.CreateFont (font_spec)
|
||||
self.text = text
|
||||
self.width = self.height = 0
|
||||
# set up message handlers
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
def OnAttachedObjectDeath(self):
|
||||
docview.ScrollView.OnAttachedObjectDeath(self)
|
||||
del self.font
|
||||
|
||||
def SetFont (self, new_font):
|
||||
# Change font on the fly
|
||||
self.font = win32ui.CreateFont (new_font)
|
||||
# redraw the entire client window
|
||||
selfInvalidateRect (None)
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
self.width = win32api.LOWORD(lParam)
|
||||
self.height = win32api.HIWORD(lParam)
|
||||
|
||||
def OnPrepareDC (self, dc, printinfo):
|
||||
# Set up the DC for forthcoming OnDraw call
|
||||
self.SetScrollSizes(win32con.MM_TEXT, (100,100))
|
||||
dc.SetTextColor (win32api.RGB(0,0,255))
|
||||
dc.SetBkColor (win32api.GetSysColor (win32con.COLOR_WINDOW))
|
||||
dc.SelectObject (self.font)
|
||||
dc.SetTextAlign (win32con.TA_CENTER | win32con.TA_BASELINE)
|
||||
|
||||
def OnDraw (self, dc):
|
||||
if (self.width == 0 and self.height == 0):
|
||||
left, top, right, bottom = self.GetClientRect()
|
||||
self.width = right - left
|
||||
self.height = bottom - top
|
||||
x, y = self.width // 2, self.height // 2
|
||||
dc.TextOut (x, y, self.text)
|
||||
|
||||
def FontDemo():
|
||||
# create doc/view
|
||||
template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, None, None, FontView)
|
||||
doc=template.OpenDocumentFile(None)
|
||||
doc.SetTitle ('Font Demo')
|
||||
# print "template is ", template, "obj is", template._obj_
|
||||
template.close()
|
||||
# print "closed"
|
||||
# del template
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
FontDemo()
|
|
@ -1,68 +0,0 @@
|
|||
# GUI Demo - just a worker script to invoke all the other demo/test scripts.
|
||||
import win32ui
|
||||
import __main__
|
||||
import sys
|
||||
import regutil
|
||||
import win32api
|
||||
|
||||
demos = [ \
|
||||
# ('Font', 'import fontdemo;fontdemo.FontDemo()'),
|
||||
('Open GL Demo', 'import openGLDemo;openGLDemo.test()'),
|
||||
('Threaded GUI', 'import threadedgui;threadedgui.ThreadedDemo()'),
|
||||
('Tree View Demo', 'import hiertest;hiertest.demoboth()'),
|
||||
('3-Way Splitter Window', 'import splittst;splittst.demo()'),
|
||||
('Custom Toolbars and Tooltips', 'import toolbar;toolbar.test()'),
|
||||
('Progress Bar', 'import progressbar;progressbar.demo()'),
|
||||
('Slider Control', 'import sliderdemo;sliderdemo.demo()'),
|
||||
('Dynamic window creation', 'import createwin;createwin.demo()'),
|
||||
('Various Dialog demos', 'import dlgtest;dlgtest.demo()'),
|
||||
('OCX Control Demo', 'from ocx import ocxtest;ocxtest.demo()'),
|
||||
('OCX Serial Port Demo', 'from ocx import ocxserialtest; ocxserialtest.test()'),
|
||||
('IE4 Control Demo', 'from ocx import webbrowser; webbrowser.Demo("http://www.python.org")'),
|
||||
]
|
||||
|
||||
def demo():
|
||||
try:
|
||||
# seeif I can locate the demo files.
|
||||
import fontdemo
|
||||
except ImportError:
|
||||
# else put the demos direectory on the path (if not already)
|
||||
try:
|
||||
instPath = regutil.GetRegistryDefaultValue(regutil.BuildDefaultPythonKey() + "\\InstallPath")
|
||||
except win32api.error:
|
||||
print("The InstallPath can not be located, and the Demos directory is not on the path")
|
||||
instPath="."
|
||||
|
||||
demosDir = win32ui.FullPath(instPath + "\\Demos")
|
||||
for path in sys.path:
|
||||
if win32ui.FullPath(path)==demosDir:
|
||||
break
|
||||
else:
|
||||
sys.path.append(demosDir)
|
||||
import fontdemo
|
||||
|
||||
import sys
|
||||
if "/go" in sys.argv:
|
||||
for name, cmd in demos:
|
||||
try:
|
||||
exec(cmd)
|
||||
except:
|
||||
print("Demo of %s failed - %s:%s" % (cmd,sys.exc_info()[0], sys.exc_info()[1]))
|
||||
return
|
||||
# Otherwise allow the user to select the demo to run
|
||||
|
||||
import pywin.dialogs.list
|
||||
while 1:
|
||||
rc = pywin.dialogs.list.SelectFromLists( "Select a Demo", demos, ['Demo Title'] )
|
||||
if rc is None:
|
||||
break
|
||||
title, cmd = demos[rc]
|
||||
try:
|
||||
exec(cmd)
|
||||
except:
|
||||
print("Demo of %s failed - %s:%s" % (title,sys.exc_info()[0], sys.exc_info()[1]))
|
||||
|
||||
if __name__==__main__.__name__:
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
demo()
|
|
@ -1,104 +0,0 @@
|
|||
import win32ui
|
||||
import os
|
||||
import commctrl
|
||||
|
||||
from pywin.tools import hierlist
|
||||
from pywin.mfc import docview, window
|
||||
|
||||
# directory listbox
|
||||
# This has obvious limitations - doesnt track subdirs, etc. Demonstrates
|
||||
# simple use of Python code for querying the tree as needed.
|
||||
# Only use strings, and lists of strings (from curdir())
|
||||
class DirHierList(hierlist.HierList):
|
||||
def __init__(self, root, listBoxID = win32ui.IDC_LIST1):
|
||||
hierlist.HierList.__init__(self, root, win32ui.IDB_HIERFOLDERS, listBoxID)
|
||||
def GetText(self, item):
|
||||
return os.path.basename(item)
|
||||
def GetSubList(self, item):
|
||||
if os.path.isdir(item):
|
||||
ret = [os.path.join(item, fname) for fname in os.listdir(item)]
|
||||
else:
|
||||
ret = None
|
||||
return ret
|
||||
# if the item is a dir, it is expandable.
|
||||
def IsExpandable(self, item):
|
||||
return os.path.isdir(item)
|
||||
def GetSelectedBitmapColumn(self, item):
|
||||
return self.GetBitmapColumn(item)+6 # Use different color for selection
|
||||
|
||||
class TestDocument(docview.Document):
|
||||
def __init__(self, template):
|
||||
docview.Document.__init__(self, template)
|
||||
self.hierlist = hierlist.HierListWithItems(HLIFileDir("\\"), win32ui.IDB_HIERFOLDERS, win32ui.AFX_IDW_PANE_FIRST)
|
||||
|
||||
class HierListView(docview.TreeView):
|
||||
def OnInitialUpdate(self):
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
self.hierList = self.GetDocument().hierlist
|
||||
self.hierList.HierInit(self.GetParent())
|
||||
self.hierList.SetStyle(commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS)
|
||||
return rc
|
||||
|
||||
class HierListFrame(window.MDIChildWnd):
|
||||
pass
|
||||
|
||||
def GetTestRoot():
|
||||
tree1 = ('Tree 1',[('Item 1','Item 1 data'),'Item 2',3])
|
||||
tree2 = ('Tree 2',[('Item 2.1','Item 2 data'),'Item 2.2',2.3])
|
||||
return ('Root',[tree1,tree2,'Item 3'])
|
||||
|
||||
def demoboth():
|
||||
template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, TestDocument, HierListFrame, HierListView)
|
||||
template.OpenDocumentFile(None).SetTitle("Hierlist demo")
|
||||
|
||||
demomodeless()
|
||||
|
||||
def demomodeless():
|
||||
testList2=DirHierList("\\")
|
||||
dlg=hierlist.HierDialog('hier list test',testList2)
|
||||
dlg.CreateWindow()
|
||||
|
||||
def demodlg ():
|
||||
testList2=DirHierList("\\")
|
||||
dlg=hierlist.HierDialog('hier list test',testList2)
|
||||
dlg.DoModal()
|
||||
|
||||
def demo():
|
||||
template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, TestDocument, HierListFrame, HierListView)
|
||||
template.OpenDocumentFile(None).SetTitle("Hierlist demo")
|
||||
|
||||
#
|
||||
# Demo/Test for HierList items.
|
||||
#
|
||||
# Easy to make a better directory program.
|
||||
#
|
||||
class HLIFileDir(hierlist.HierListItem):
|
||||
def __init__( self, filename ):
|
||||
self.filename = filename
|
||||
hierlist.HierListItem.__init__(self)
|
||||
def GetText(self):
|
||||
try:
|
||||
return "%-20s %d bytes" % (os.path.basename(self.filename), os.stat(self.filename)[6])
|
||||
except os.error as details:
|
||||
return "%-20s - %s" % (self.filename, details[1])
|
||||
|
||||
def IsExpandable(self):
|
||||
return os.path.isdir(self.filename)
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
for newname in os.listdir(self.filename):
|
||||
if newname not in ['.', '..']:
|
||||
ret.append( HLIFileDir( os.path.join(self.filename,newname ) ) )
|
||||
return ret
|
||||
|
||||
|
||||
def demohli():
|
||||
template = docview.DocTemplate(win32ui.IDR_PYTHONTYPE, TestDocument, hierlist.HierListFrame, hierlist.HierListView)
|
||||
template.OpenDocumentFile(None).SetTitle("Hierlist demo")
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.HaveGoodGUI():
|
||||
demoboth()
|
||||
else:
|
||||
demodlg()
|
|
@ -1,12 +0,0 @@
|
|||
# Run this as a python script, to gray "close" off the edit window system menu.
|
||||
from pywin.framework import interact
|
||||
import win32con
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
win=interact.edit.currentView.GetParent()
|
||||
menu=win.GetSystemMenu()
|
||||
id=menu.GetMenuItemID(6)
|
||||
menu.EnableMenuItem(id,win32con.MF_BYCOMMAND|win32con.MF_GRAYED)
|
||||
print("The interactive window's 'Close' menu item is now disabled.")
|
|
@ -1,49 +0,0 @@
|
|||
# This is a sample file, and shows the basic framework for using an "Object" based
|
||||
# document, rather than a "filename" based document.
|
||||
# This is referenced by the Pythonwin .html documentation.
|
||||
|
||||
# In the example below, the OpenObject() method is used instead of OpenDocumentFile,
|
||||
# and all the core MFC document open functionality is retained.
|
||||
|
||||
import win32ui
|
||||
from pywin.mfc import docview
|
||||
|
||||
class object_template (docview.DocTemplate):
|
||||
def __init__(self):
|
||||
docview.DocTemplate.__init__(self, None, None, None, object_view)
|
||||
def OpenObject(self, object): # Use this instead of OpenDocumentFile.
|
||||
# Look for existing open document
|
||||
for doc in self.GetDocumentList():
|
||||
print("document is ", doc)
|
||||
if doc.object is object:
|
||||
doc.GetFirstView().ActivateFrame()
|
||||
return doc
|
||||
# not found - new one.
|
||||
doc = object_document(self, object)
|
||||
frame = self.CreateNewFrame(doc)
|
||||
doc.OnNewDocument()
|
||||
doc.SetTitle(str(object))
|
||||
self.InitialUpdateFrame(frame, doc)
|
||||
return doc
|
||||
|
||||
class object_document (docview.Document):
|
||||
def __init__(self, template, object):
|
||||
docview.Document.__init__(self, template)
|
||||
self.object = object
|
||||
def OnOpenDocument (self, name):
|
||||
raise RuntimeError("Should not be called if template strings set up correctly")
|
||||
return 0
|
||||
|
||||
class object_view (docview.EditView):
|
||||
def OnInitialUpdate (self):
|
||||
self.ReplaceSel("Object is %s" % repr(self.GetDocument().object))
|
||||
|
||||
def demo ():
|
||||
t = object_template()
|
||||
d = t.OpenObject(win32ui)
|
||||
return (t, d)
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
demo()
|
|
@ -1,54 +0,0 @@
|
|||
# Utilities for the demos
|
||||
|
||||
import sys, win32api, win32con, win32ui
|
||||
|
||||
NotScriptMsg = """\
|
||||
This demo program is not designed to be run as a Script, but is
|
||||
probably used by some other test program. Please try another demo.
|
||||
"""
|
||||
|
||||
NeedGUIMsg = """\
|
||||
This demo program can only be run from inside of Pythonwin
|
||||
|
||||
You must start Pythonwin, and select 'Run' from the toolbar or File menu
|
||||
"""
|
||||
|
||||
|
||||
NeedAppMsg = """\
|
||||
This demo program is a 'Pythonwin Application'.
|
||||
|
||||
It is more demo code than an example of Pythonwin's capabilities.
|
||||
|
||||
To run it, you must execute the command:
|
||||
pythonwin.exe /app "%s"
|
||||
|
||||
Would you like to execute it now?
|
||||
"""
|
||||
|
||||
def NotAScript():
|
||||
import win32ui
|
||||
win32ui.MessageBox(NotScriptMsg, "Demos")
|
||||
|
||||
def NeedGoodGUI():
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
rc = HaveGoodGUI()
|
||||
if not rc:
|
||||
win32ui.MessageBox(NeedGUIMsg, "Demos")
|
||||
return rc
|
||||
|
||||
def NeedApp():
|
||||
import win32ui
|
||||
rc = win32ui.MessageBox(NeedAppMsg % sys.argv[0], "Demos", win32con.MB_YESNO)
|
||||
if rc==win32con.IDYES:
|
||||
try:
|
||||
parent = win32ui.GetMainFrame().GetSafeHwnd()
|
||||
win32api.ShellExecute(parent, None, 'pythonwin.exe', '/app "%s"' % sys.argv[0], None, 1)
|
||||
except win32api.error as details:
|
||||
win32ui.MessageBox("Error executing command - %s" % (details), "Demos")
|
||||
|
||||
|
||||
from pywin.framework.app import HaveGoodGUI
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
demoutils.NotAScript()
|
|
@ -1,84 +0,0 @@
|
|||
# By Bradley Schatz
|
||||
# simple flash/python application demonstrating bidirectional
|
||||
# communicaion between flash and python. Click the sphere to see
|
||||
# behavior. Uses Bounce.swf from FlashBounce.zip, available from
|
||||
# http://pages.cpsc.ucalgary.ca/~saul/vb_examples/tutorial12/
|
||||
|
||||
# Update to the path of the .swf file (note it could be a true URL)
|
||||
flash_url = "c:\\bounce.swf"
|
||||
|
||||
import win32ui, win32con, win32api, regutil
|
||||
from pywin.mfc import window, activex
|
||||
from win32com.client import gencache
|
||||
import sys
|
||||
|
||||
FlashModule = gencache.EnsureModule("{D27CDB6B-AE6D-11CF-96B8-444553540000}", 0, 1, 0)
|
||||
|
||||
if FlashModule is None:
|
||||
raise ImportError("Flash does not appear to be installed.")
|
||||
|
||||
class MyFlashComponent(activex.Control, FlashModule.ShockwaveFlash):
|
||||
def __init__(self):
|
||||
activex.Control.__init__(self)
|
||||
FlashModule.ShockwaveFlash.__init__(self)
|
||||
self.x = 50
|
||||
self.y = 50
|
||||
self.angle = 30
|
||||
self.started = 0
|
||||
|
||||
def OnFSCommand(self, command, args):
|
||||
print("FSCommend" , command, args)
|
||||
self.x = self.x + 20
|
||||
self.y = self.y + 20
|
||||
self.angle = self.angle + 20
|
||||
if self.x > 200 or self.y > 200:
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
if self.angle > 360:
|
||||
self.angle = 0
|
||||
self.SetVariable("xVal", self.x)
|
||||
self.SetVariable("yVal", self.y)
|
||||
self.SetVariable("angle", self.angle)
|
||||
self.TPlay("_root.mikeBall")
|
||||
|
||||
def OnProgress(self, percentDone):
|
||||
print("PercentDone", percentDone)
|
||||
def OnReadyStateChange(self, newState):
|
||||
# 0=Loading, 1=Uninitialized, 2=Loaded, 3=Interactive, 4=Complete
|
||||
print("State", newState)
|
||||
|
||||
|
||||
class BrowserFrame(window.MDIChildWnd):
|
||||
def __init__(self, url = None):
|
||||
if url is None:
|
||||
self.url = regutil.GetRegisteredHelpFile("Main Python Documentation")
|
||||
else:
|
||||
self.url = url
|
||||
pass # Dont call base class doc/view version...
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx = MyFlashComponent()
|
||||
self.ocx.CreateControl("Flash Player", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000)
|
||||
self.ocx.LoadMovie(0,flash_url)
|
||||
self.ocx.Play()
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
def OnSize (self, params):
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx.SetWindowPos(0, rect, 0)
|
||||
|
||||
def Demo():
|
||||
url = None
|
||||
if len(sys.argv)>1:
|
||||
url = win32api.GetFullPathName(sys.argv[1])
|
||||
f = BrowserFrame(url)
|
||||
f.Create("Flash Player")
|
||||
|
||||
if __name__=='__main__':
|
||||
Demo()
|
|
@ -1,127 +0,0 @@
|
|||
# This demo uses some of the Microsoft Office components.
|
||||
#
|
||||
# It was taken from an MSDN article showing how to embed excel.
|
||||
# It is not comlpete yet, but it _does_ show an Excel spreadsheet in a frame!
|
||||
#
|
||||
|
||||
import win32ui, win32uiole, win32con, regutil
|
||||
from pywin.mfc import window, activex, object, docview
|
||||
from win32com.client import gencache
|
||||
|
||||
#WordModule = gencache.EnsureModule('{00020905-0000-0000-C000-000000000046}', 1033, 8, 0)
|
||||
#if WordModule is None:
|
||||
# raise ImportError, "Microsoft Word version 8 does not appear to be installed."
|
||||
|
||||
|
||||
class OleClientItem(object.CmdTarget):
|
||||
def __init__(self, doc):
|
||||
object.CmdTarget.__init__(self, win32uiole.CreateOleClientItem(doc))
|
||||
|
||||
def OnGetItemPosition(self):
|
||||
# For now return a hard-coded rect.
|
||||
return (10, 10, 210, 210)
|
||||
|
||||
def OnActivate(self):
|
||||
# Allow only one inplace activate item per frame
|
||||
view = self.GetActiveView()
|
||||
item = self.GetDocument().GetInPlaceActiveItem(view)
|
||||
if item is not None and item._obj_ != self._obj_:
|
||||
item.Close()
|
||||
self._obj_.OnActivate()
|
||||
|
||||
def OnChange(self, oleNotification, dwParam):
|
||||
self._obj_.OnChange(oleNotification, dwParam)
|
||||
self.GetDocument().UpdateAllViews(None)
|
||||
|
||||
def OnChangeItemPosition(self, rect):
|
||||
# During in-place activation CEmbed_ExcelCntrItem::OnChangeItemPosition
|
||||
# is called by the server to change the position of the in-place
|
||||
# window. Usually, this is a result of the data in the server
|
||||
# document changing such that the extent has changed or as a result
|
||||
# of in-place resizing.
|
||||
#
|
||||
# The default here is to call the base class, which will call
|
||||
# COleClientItem::SetItemRects to move the item
|
||||
# to the new position.
|
||||
if not self._obj_.OnChangeItemPosition(self, rect):
|
||||
return 0
|
||||
|
||||
# TODO: update any cache you may have of the item's rectangle/extent
|
||||
return 1
|
||||
|
||||
class OleDocument(object.CmdTarget):
|
||||
def __init__(self, template):
|
||||
object.CmdTarget.__init__(self, win32uiole.CreateOleDocument(template))
|
||||
self.EnableCompoundFile()
|
||||
|
||||
class ExcelView(docview.ScrollView):
|
||||
def OnInitialUpdate(self):
|
||||
self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS)
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
self.SetScrollSizes(win32con.MM_TEXT, (100, 100))
|
||||
rc = self._obj_.OnInitialUpdate()
|
||||
self.EmbedExcel()
|
||||
return rc
|
||||
|
||||
def EmbedExcel(self):
|
||||
doc = self.GetDocument()
|
||||
self.clientItem = OleClientItem(doc)
|
||||
self.clientItem.CreateNewItem("Excel.Sheet")
|
||||
self.clientItem.DoVerb(-1, self)
|
||||
doc.UpdateAllViews(None)
|
||||
|
||||
def OnDraw(self, dc):
|
||||
doc = self.GetDocument()
|
||||
pos = doc.GetStartPosition()
|
||||
clientItem, pos = doc.GetNextItem(pos)
|
||||
clientItem.Draw(dc, (10, 10, 210, 210) )
|
||||
|
||||
# Special handling of OnSetFocus and OnSize are required for a container
|
||||
# when an object is being edited in-place.
|
||||
def OnSetFocus(self, msg):
|
||||
item = self.GetDocument().GetInPlaceActiveItem(self)
|
||||
if item is not None and item.GetItemState()==win32uiole.COleClientItem_activeUIState:
|
||||
wnd = item.GetInPlaceWindow()
|
||||
if wnd is not None:
|
||||
wnd.SetFocus()
|
||||
return 0 # Dont get the base version called.
|
||||
return 1 # Call the base version.
|
||||
|
||||
def OnSize (self, params):
|
||||
item = self.GetDocument().GetInPlaceActiveItem(self)
|
||||
if item is not None:
|
||||
item.SetItemRects()
|
||||
return 1 # do call the base!
|
||||
|
||||
class OleTemplate(docview.DocTemplate):
|
||||
def __init__(self, resourceId=None, MakeDocument=None, MakeFrame=None, MakeView=None):
|
||||
if MakeDocument is None: MakeDocument = OleDocument
|
||||
if MakeView is None: MakeView = ExcelView
|
||||
docview.DocTemplate.__init__(self, resourceId, MakeDocument, MakeFrame, MakeView)
|
||||
|
||||
class WordFrame(window.MDIChildWnd):
|
||||
def __init__(self, doc = None):
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
# Dont call base class doc/view version...
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx = MyWordControl()
|
||||
self.ocx.CreateControl("Microsoft Word", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 20000)
|
||||
|
||||
def Demo():
|
||||
import sys, win32api
|
||||
docName = None
|
||||
if len(sys.argv)>1:
|
||||
docName = win32api.GetFullPathName(sys.argv[1])
|
||||
OleTemplate().OpenDocumentFile(None)
|
||||
# f = WordFrame(docName)
|
||||
# f.Create("Microsoft Office")
|
||||
|
||||
if __name__=='__main__':
|
||||
Demo()
|
|
@ -1,101 +0,0 @@
|
|||
# ocxserialtest.py
|
||||
#
|
||||
# Sample that uses the mscomm OCX to talk to a serial
|
||||
# device.
|
||||
|
||||
# Very simple - queries a modem for ATI responses
|
||||
|
||||
import win32ui, win32uiole
|
||||
import win32con
|
||||
from pywin.mfc import dialog, activex
|
||||
from win32com.client import gencache
|
||||
import pythoncom
|
||||
|
||||
SERIAL_SETTINGS = '19200,n,8,1'
|
||||
SERIAL_PORT = 2
|
||||
|
||||
win32ui.DoWaitCursor(1)
|
||||
serialModule = gencache.EnsureModule("{648A5603-2C6E-101B-82B6-000000000014}", 0, 1, 1)
|
||||
win32ui.DoWaitCursor(0)
|
||||
if serialModule is None:
|
||||
raise ImportError("MS COMM Control does not appear to be installed on the PC")
|
||||
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP \
|
||||
| win32con.WS_VISIBLE | win32con.WS_CAPTION \
|
||||
| win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
dlg = [ ["Very Basic Terminal",
|
||||
(0, 0, 350, 180), style, None, (8, "MS Sans Serif")], ]
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
dlg.append(["RICHEDIT", None, 132, (5, 5, 340, 170),s | win32con.ES_WANTRETURN | win32con.ES_MULTILINE | win32con.ES_AUTOVSCROLL | win32con.WS_VSCROLL])
|
||||
return dlg
|
||||
|
||||
|
||||
####################################
|
||||
#
|
||||
# Serial Control
|
||||
#
|
||||
class MySerialControl(activex.Control, serialModule.MSComm):
|
||||
def __init__(self, parent):
|
||||
activex.Control.__init__(self)
|
||||
serialModule.MSComm.__init__(self)
|
||||
self.parent = parent
|
||||
def OnComm(self):
|
||||
self.parent.OnComm()
|
||||
|
||||
class TestSerDialog(dialog.Dialog):
|
||||
def __init__(self, *args):
|
||||
dialog.Dialog.__init__(*(self,)+args)
|
||||
self.olectl = None
|
||||
def OnComm(self):
|
||||
event = self.olectl.CommEvent
|
||||
if event == serialModule.OnCommConstants.comEvReceive:
|
||||
self.editwindow.ReplaceSel(self.olectl.Input)
|
||||
|
||||
def OnKey(self, key):
|
||||
if self.olectl:
|
||||
self.olectl.Output = chr(key)
|
||||
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.editwindow = self.GetDlgItem(132)
|
||||
self.editwindow.HookAllKeyStrokes(self.OnKey)
|
||||
|
||||
self.olectl = MySerialControl(self)
|
||||
try:
|
||||
self.olectl.CreateControl("OCX",
|
||||
win32con.WS_TABSTOP | win32con.WS_VISIBLE,
|
||||
(7,43,500,300), self._obj_, 131)
|
||||
except win32ui.error:
|
||||
self.MessageBox("The Serial Control could not be created")
|
||||
self.olectl = None
|
||||
self.EndDialog(win32con.IDCANCEL)
|
||||
if self.olectl:
|
||||
self.olectl.Settings = SERIAL_SETTINGS
|
||||
self.olectl.CommPort = SERIAL_PORT
|
||||
self.olectl.RThreshold = 1
|
||||
try:
|
||||
self.olectl.PortOpen = 1
|
||||
except pythoncom.com_error as details:
|
||||
print("Could not open the specified serial port - %s" % (details.excepinfo[2]))
|
||||
self.EndDialog(win32con.IDCANCEL)
|
||||
return rc
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
if self.olectl:
|
||||
try:
|
||||
self.olectl.PortOpen = 0
|
||||
except pythoncom.com_error as details:
|
||||
print("Error closing port - %s" % (details.excepinfo[2]))
|
||||
return dialog.Dialog.OnDestroy(self, msg)
|
||||
|
||||
def test():
|
||||
d = TestSerDialog(MakeDlgTemplate() )
|
||||
d.DoModal()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
test()
|
|
@ -1,186 +0,0 @@
|
|||
# OCX Tester for Pythonwin
|
||||
#
|
||||
# This file _is_ ready to run. All that is required is that the OCXs being tested
|
||||
# are installed on your machine.
|
||||
#
|
||||
# The .py files behind the OCXs will be automatically generated and imported.
|
||||
|
||||
from pywin.mfc import dialog, window, activex
|
||||
import win32ui, win32uiole
|
||||
import win32con
|
||||
import os, sys, win32api, glob
|
||||
from win32com.client import gencache
|
||||
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
dlg = [ ["OCX Demos", (0, 0, 350, 350), style, None, (8, "MS Sans Serif")], ]
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
# dlg.append([131, None, 130, (5, 40, 110, 48),
|
||||
# s | win32con.LBS_NOTIFY | win32con.LBS_SORT | win32con.LBS_NOINTEGRALHEIGHT | win32con.WS_VSCROLL | win32con.WS_BORDER])
|
||||
# dlg.append(["{8E27C92B-1264-101C-8A2F-040224009C02}", None, 131, (5, 40, 110, 48),win32con.WS_TABSTOP])
|
||||
|
||||
dlg.append([128, "About", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
s = win32con.BS_PUSHBUTTON | s
|
||||
dlg.append([128, "Close", win32con.IDCANCEL, (124, 22, 50, 14), s])
|
||||
|
||||
return dlg
|
||||
|
||||
####################################
|
||||
#
|
||||
# Calendar test code
|
||||
#
|
||||
|
||||
def GetTestCalendarClass():
|
||||
global calendarParentModule
|
||||
win32ui.DoWaitCursor(1)
|
||||
calendarParentModule = gencache.EnsureModule("{8E27C92E-1264-101C-8A2F-040224009C02}", 0, 7, 0)
|
||||
win32ui.DoWaitCursor(0)
|
||||
if calendarParentModule is None:
|
||||
return None
|
||||
|
||||
class TestCalDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
|
||||
class MyCal(activex.Control, calendarParentModule.Calendar):
|
||||
def OnAfterUpdate(self):
|
||||
print("OnAfterUpdate")
|
||||
def OnClick(self):
|
||||
print("OnClick")
|
||||
def OnDblClick(self):
|
||||
print("OnDblClick")
|
||||
def OnKeyDown(self, KeyCode, Shift):
|
||||
print("OnKeyDown", KeyCode, Shift)
|
||||
def OnKeyPress(self, KeyAscii):
|
||||
print("OnKeyPress", KeyAscii)
|
||||
def OnKeyUp(self, KeyCode, Shift):
|
||||
print("OnKeyUp", KeyCode, Shift)
|
||||
def OnBeforeUpdate(self, Cancel):
|
||||
print("OnBeforeUpdate", Cancel)
|
||||
def OnNewMonth(self):
|
||||
print("OnNewMonth")
|
||||
def OnNewYear(self):
|
||||
print("OnNewYear")
|
||||
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.olectl = MyCal()
|
||||
try:
|
||||
self.olectl.CreateControl("OCX", win32con.WS_TABSTOP | win32con.WS_VISIBLE, (7,43,500,300), self._obj_, 131)
|
||||
except win32ui.error:
|
||||
self.MessageBox("The Calendar Control could not be created")
|
||||
self.olectl = None
|
||||
self.EndDialog(win32con.IDCANCEL)
|
||||
|
||||
return rc
|
||||
def OnOK(self):
|
||||
self.olectl.AboutBox()
|
||||
|
||||
return TestCalDialog
|
||||
|
||||
|
||||
####################################
|
||||
#
|
||||
# Video Control
|
||||
#
|
||||
def GetTestVideoModule():
|
||||
global videoControlModule, videoControlFileName
|
||||
win32ui.DoWaitCursor(1)
|
||||
videoControlModule = gencache.EnsureModule("{05589FA0-C356-11CE-BF01-00AA0055595A}", 0, 2, 0)
|
||||
win32ui.DoWaitCursor(0)
|
||||
if videoControlModule is None:
|
||||
return None
|
||||
fnames = glob.glob(os.path.join(win32api.GetWindowsDirectory(), "*.avi"))
|
||||
if not fnames:
|
||||
print("No AVI files available in system directory")
|
||||
return None
|
||||
videoControlFileName = fnames[0]
|
||||
return videoControlModule
|
||||
|
||||
def GetTestVideoDialogClass():
|
||||
if GetTestVideoModule() is None:
|
||||
return None
|
||||
class TestVideoDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
try:
|
||||
self.olectl = activex.MakeControlInstance(videoControlModule.ActiveMovie)
|
||||
self.olectl.CreateControl("", win32con.WS_TABSTOP | win32con.WS_VISIBLE, (7,43,500,300), self._obj_, 131)
|
||||
except win32ui.error:
|
||||
self.MessageBox("The Video Control could not be created")
|
||||
self.olectl = None
|
||||
self.EndDialog(win32con.IDCANCEL)
|
||||
return
|
||||
|
||||
self.olectl.FileName = videoControlFileName
|
||||
# self.olectl.Run()
|
||||
return rc
|
||||
def OnOK(self):
|
||||
self.olectl.AboutBox()
|
||||
return TestVideoDialog
|
||||
|
||||
###############
|
||||
#
|
||||
# An OCX in an MDI Frame
|
||||
#
|
||||
class OCXFrame(window.MDIChildWnd):
|
||||
def __init__(self):
|
||||
pass # Dont call base class doc/view version...
|
||||
def Create(self, controlClass, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx = controlClass()
|
||||
self.ocx.CreateControl("", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000)
|
||||
|
||||
def MDITest():
|
||||
calendarParentModule = gencache.EnsureModule("{8E27C92E-1264-101C-8A2F-040224009C02}", 0, 7, 0)
|
||||
class MyCal(activex.Control, calendarParentModule.Calendar):
|
||||
def OnAfterUpdate(self):
|
||||
print("OnAfterUpdate")
|
||||
def OnClick(self):
|
||||
print("OnClick")
|
||||
|
||||
f = OCXFrame()
|
||||
f.Create(MyCal, "Calendar Test")
|
||||
|
||||
|
||||
def test1():
|
||||
klass = GetTestCalendarClass()
|
||||
if klass is None:
|
||||
print("Can not test the MSAccess Calendar control - it does not appear to be installed")
|
||||
return
|
||||
|
||||
d = klass(MakeDlgTemplate() )
|
||||
d.DoModal()
|
||||
|
||||
def test2():
|
||||
klass = GetTestVideoDialogClass()
|
||||
if klass is None:
|
||||
print("Can not test the Video OCX - it does not appear to be installed,")
|
||||
print("or no AVI files can be found.")
|
||||
return
|
||||
d = klass(MakeDlgTemplate() )
|
||||
d.DoModal()
|
||||
d = None
|
||||
|
||||
def test3():
|
||||
d = TestCOMMDialog(MakeDlgTemplate() )
|
||||
d.DoModal()
|
||||
d = None
|
||||
|
||||
def testall():
|
||||
test1()
|
||||
test2()
|
||||
|
||||
def demo():
|
||||
testall()
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
testall()
|
|
@ -1,55 +0,0 @@
|
|||
# This demo uses the IE4 Web Browser control.
|
||||
|
||||
# It catches an "OnNavigate" event, and updates the frame title.
|
||||
# (event stuff by Neil Hodgson)
|
||||
|
||||
import win32ui, win32con, win32api, regutil
|
||||
from pywin.mfc import window, activex
|
||||
from win32com.client import gencache
|
||||
import sys
|
||||
|
||||
WebBrowserModule = gencache.EnsureModule("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1)
|
||||
if WebBrowserModule is None:
|
||||
raise ImportError("IE4 does not appear to be installed.")
|
||||
|
||||
class MyWebBrowser(activex.Control, WebBrowserModule.WebBrowser):
|
||||
def OnBeforeNavigate2(self, pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel):
|
||||
self.GetParent().OnNavigate(URL)
|
||||
#print "BeforeNavigate2", pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel
|
||||
|
||||
class BrowserFrame(window.MDIChildWnd):
|
||||
def __init__(self, url = None):
|
||||
if url is None:
|
||||
self.url = regutil.GetRegisteredHelpFile("Main Python Documentation")
|
||||
if self.url is None:
|
||||
self.url = "http://www.python.org"
|
||||
else:
|
||||
self.url = url
|
||||
pass # Dont call base class doc/view version...
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx = MyWebBrowser()
|
||||
self.ocx.CreateControl("Web Browser", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000)
|
||||
self.ocx.Navigate(self.url)
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
def OnSize (self, params):
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.ocx.SetWindowPos(0, rect, 0)
|
||||
def OnNavigate(self, url):
|
||||
title = "Web Browser - %s" % (url,)
|
||||
self.SetWindowText(title)
|
||||
|
||||
def Demo(url=None):
|
||||
if url is None and len(sys.argv)>1:
|
||||
url = win32api.GetFullPathName(sys.argv[1])
|
||||
f = BrowserFrame(url)
|
||||
f.Create("Web Browser")
|
||||
|
||||
if __name__=='__main__':
|
||||
Demo()
|
|
@ -1,358 +0,0 @@
|
|||
# Ported from the win32 and MFC OpenGL Samples.
|
||||
|
||||
from pywin.mfc import docview
|
||||
import sys
|
||||
try:
|
||||
from OpenGL.GL import *
|
||||
from OpenGL.GLU import *
|
||||
except ImportError:
|
||||
print("The OpenGL extensions do not appear to be installed.")
|
||||
print("This Pythonwin demo can not run")
|
||||
sys.exit(1)
|
||||
|
||||
import win32con
|
||||
import win32ui
|
||||
import win32api
|
||||
import timer
|
||||
|
||||
PFD_TYPE_RGBA = 0
|
||||
PFD_TYPE_COLORINDEX = 1
|
||||
PFD_MAIN_PLANE = 0
|
||||
PFD_OVERLAY_PLANE = 1
|
||||
PFD_UNDERLAY_PLANE = (-1)
|
||||
PFD_DOUBLEBUFFER = 0x00000001
|
||||
PFD_STEREO = 0x00000002
|
||||
PFD_DRAW_TO_WINDOW = 0x00000004
|
||||
PFD_DRAW_TO_BITMAP = 0x00000008
|
||||
PFD_SUPPORT_GDI = 0x00000010
|
||||
PFD_SUPPORT_OPENGL = 0x00000020
|
||||
PFD_GENERIC_FORMAT = 0x00000040
|
||||
PFD_NEED_PALETTE = 0x00000080
|
||||
PFD_NEED_SYSTEM_PALETTE = 0x00000100
|
||||
PFD_SWAP_EXCHANGE = 0x00000200
|
||||
PFD_SWAP_COPY = 0x00000400
|
||||
PFD_SWAP_LAYER_BUFFERS = 0x00000800
|
||||
PFD_GENERIC_ACCELERATED = 0x00001000
|
||||
PFD_DEPTH_DONTCARE = 0x20000000
|
||||
PFD_DOUBLEBUFFER_DONTCARE = 0x40000000
|
||||
PFD_STEREO_DONTCARE = 0x80000000
|
||||
|
||||
|
||||
#threeto8 = [0, 0o111>>1, 0o222>>1, 0o333>>1, 0o444>>1, 0o555>>1, 0o666>>1, 0o377]
|
||||
threeto8 = [0, 73>>1, 146>>1, 219>>1, 292>>1, 365>>1, 438>>1, 255]
|
||||
twoto8 = [0, 0x55, 0xaa, 0xff]
|
||||
oneto8 = [0, 255]
|
||||
|
||||
def ComponentFromIndex(i, nbits, shift):
|
||||
# val = (unsigned char) (i >> shift);
|
||||
val = (i >> shift) & 0xF;
|
||||
if nbits==1:
|
||||
val = val & 0x1
|
||||
return oneto8[val]
|
||||
elif nbits==2:
|
||||
val = val & 0x3
|
||||
return twoto8[val]
|
||||
elif nbits==3:
|
||||
val = val & 0x7
|
||||
return threeto8[val]
|
||||
else:
|
||||
return 0;
|
||||
|
||||
OpenGLViewParent=docview.ScrollView
|
||||
class OpenGLView(OpenGLViewParent):
|
||||
def PreCreateWindow(self, cc):
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
# An OpenGL window must be created with the following flags and must not
|
||||
# include CS_PARENTDC for the class style. Refer to SetPixelFormat
|
||||
# documentation in the "Comments" section for further information.
|
||||
style = cc[5]
|
||||
style = style | win32con.WS_CLIPSIBLINGS | win32con.WS_CLIPCHILDREN
|
||||
cc = cc[0], cc[1], cc[2], cc[3], cc[4], style, cc[6], cc[7], cc[8]
|
||||
cc = self._obj_.PreCreateWindow(cc)
|
||||
return cc
|
||||
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
cx = win32api.LOWORD(lParam)
|
||||
cy = win32api.HIWORD(lParam)
|
||||
glViewport(0, 0, cx, cy)
|
||||
|
||||
if self.oldrect[2] > cx or self.oldrect[3] > cy:
|
||||
self.RedrawWindow()
|
||||
|
||||
self.OnSizeChange(cx, cy)
|
||||
|
||||
self.oldrect = self.oldrect[0], self.oldrect[1], cx, cy
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
self.SetScaleToFitSize((100,100)) # or SetScrollSizes() - A Pythonwin requirement
|
||||
return self._obj_.OnInitialUpdate()
|
||||
# return rc
|
||||
|
||||
def OnCreate(self, cs):
|
||||
self.oldrect = self.GetClientRect()
|
||||
self._InitContexts()
|
||||
self.Init()
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
self.Term()
|
||||
self._DestroyContexts()
|
||||
return OpenGLViewParent.OnDestroy(self, msg)
|
||||
|
||||
|
||||
def OnDraw(self, dc):
|
||||
self.DrawScene()
|
||||
|
||||
def OnEraseBkgnd(self, dc):
|
||||
return 1
|
||||
|
||||
# The OpenGL helpers
|
||||
def _SetupPixelFormat(self):
|
||||
dc = self.dc.GetSafeHdc()
|
||||
pfd = CreatePIXELFORMATDESCRIPTOR()
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER
|
||||
pfd.iPixelType = PFD_TYPE_RGBA
|
||||
pfd.cColorBits = 24
|
||||
pfd.cDepthBits = 32
|
||||
pfd.iLayerType = PFD_MAIN_PLANE
|
||||
pixelformat = ChoosePixelFormat(dc, pfd)
|
||||
SetPixelFormat(dc, pixelformat, pfd)
|
||||
self._CreateRGBPalette()
|
||||
|
||||
def _CreateRGBPalette(self):
|
||||
dc = self.dc.GetSafeHdc()
|
||||
n = GetPixelFormat(dc)
|
||||
pfd = DescribePixelFormat(dc, n)
|
||||
if pfd.dwFlags & PFD_NEED_PALETTE:
|
||||
n = 1 << pfd.cColorBits
|
||||
pal = []
|
||||
for i in range(n):
|
||||
this = ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift), \
|
||||
ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift), \
|
||||
ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift), \
|
||||
0
|
||||
pal.append(this)
|
||||
hpal = win32ui.CreatePalette(pal)
|
||||
self.dc.SelectPalette(hpal, 0)
|
||||
self.dc.RealizePalette()
|
||||
|
||||
def _InitContexts(self):
|
||||
self.dc = self.GetDC()
|
||||
self._SetupPixelFormat()
|
||||
hrc = wglCreateContext(self.dc.GetSafeHdc())
|
||||
wglMakeCurrent(self.dc.GetSafeHdc(), hrc)
|
||||
|
||||
def _DestroyContexts(self):
|
||||
hrc = wglGetCurrentContext()
|
||||
wglMakeCurrent(0, 0)
|
||||
if hrc: wglDeleteContext(hrc)
|
||||
|
||||
# The methods to support OpenGL
|
||||
def DrawScene(self):
|
||||
assert 0, "You must override this method"
|
||||
|
||||
def Init(self):
|
||||
assert 0, "You must override this method"
|
||||
|
||||
def OnSizeChange(self, cx, cy):
|
||||
pass
|
||||
|
||||
def Term(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestView(OpenGLView):
|
||||
|
||||
def OnSizeChange(self, right, bottom):
|
||||
glClearColor( 0.0, 0.0, 0.0, 1.0 );
|
||||
glClearDepth( 1.0 );
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
|
||||
glMatrixMode( GL_PROJECTION )
|
||||
if bottom:
|
||||
aspect = right / bottom
|
||||
else:
|
||||
aspect = 0 # When window created!
|
||||
glLoadIdentity()
|
||||
gluPerspective( 45.0, aspect, 3.0, 7.0 )
|
||||
glMatrixMode( GL_MODELVIEW )
|
||||
|
||||
near_plane = 3.0;
|
||||
far_plane = 7.0;
|
||||
maxObjectSize = 3.0;
|
||||
self.radius = near_plane + maxObjectSize/2.0;
|
||||
|
||||
|
||||
def Init(self):
|
||||
pass
|
||||
|
||||
def DrawScene(self):
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0)
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
|
||||
|
||||
glPushMatrix()
|
||||
glTranslatef(0.0, 0.0, -self.radius);
|
||||
|
||||
self._DrawCone()
|
||||
|
||||
self._DrawPyramid()
|
||||
|
||||
glPopMatrix()
|
||||
glFinish()
|
||||
|
||||
SwapBuffers( wglGetCurrentDC() )
|
||||
|
||||
def _DrawCone(self):
|
||||
glColor3f(0.0, 1.0, 0.0)
|
||||
|
||||
glPushMatrix()
|
||||
glTranslatef(-1.0, 0.0, 0.0);
|
||||
quadObj = gluNewQuadric();
|
||||
gluQuadricDrawStyle(quadObj, GLU_FILL);
|
||||
gluQuadricNormals(quadObj, GLU_SMOOTH);
|
||||
gluCylinder(quadObj, 1.0, 0.0, 1.0, 20, 10);
|
||||
# gluDeleteQuadric(quadObj);
|
||||
glPopMatrix();
|
||||
|
||||
def _DrawPyramid(self):
|
||||
glPushMatrix()
|
||||
glTranslatef(1.0, 0.0, 0.0)
|
||||
glBegin(GL_TRIANGLE_FAN)
|
||||
glColor3f(1.0, 0.0, 0.0)
|
||||
glVertex3f(0.0, 1.0, 0.0)
|
||||
glColor3f(0.0, 1.0, 0.0)
|
||||
glVertex3f(-1.0, 0.0, 0.0)
|
||||
glColor3f(0.0, 0.0, 1.0)
|
||||
glVertex3f(0.0, 0.0, 1.0)
|
||||
glColor3f(0.0, 1.0, 0.0)
|
||||
glVertex3f(1.0, 0.0, 0.0)
|
||||
glEnd()
|
||||
glPopMatrix()
|
||||
|
||||
class CubeView(OpenGLView):
|
||||
def OnSizeChange(self, right, bottom):
|
||||
glClearColor( 0.0, 0.0, 0.0, 1.0 );
|
||||
glClearDepth( 1.0 );
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
|
||||
glMatrixMode( GL_PROJECTION )
|
||||
if bottom:
|
||||
aspect = right / bottom
|
||||
else:
|
||||
aspect = 0 # When window created!
|
||||
glLoadIdentity()
|
||||
gluPerspective( 45.0, aspect, 3.0, 7.0 )
|
||||
glMatrixMode( GL_MODELVIEW )
|
||||
|
||||
near_plane = 3.0;
|
||||
far_plane = 7.0;
|
||||
maxObjectSize = 3.0;
|
||||
self.radius = near_plane + maxObjectSize/2.0;
|
||||
|
||||
def Init(self):
|
||||
self.busy = 0
|
||||
self.wAngleY = 10.0
|
||||
self.wAngleX = 1.0
|
||||
self.wAngleZ = 5.0
|
||||
self.timerid = timer.set_timer (150, self.OnTimer)
|
||||
|
||||
def OnTimer(self, id, timeVal):
|
||||
self.DrawScene()
|
||||
|
||||
def Term(self):
|
||||
timer.kill_timer(self.timerid)
|
||||
|
||||
def DrawScene(self):
|
||||
if self.busy: return
|
||||
self.busy = 1
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glTranslatef(0.0, 0.0, -self.radius);
|
||||
glRotatef(self.wAngleX, 1.0, 0.0, 0.0);
|
||||
glRotatef(self.wAngleY, 0.0, 1.0, 0.0);
|
||||
glRotatef(self.wAngleZ, 0.0, 0.0, 1.0);
|
||||
|
||||
self.wAngleX = self.wAngleX + 1.0
|
||||
self.wAngleY = self.wAngleY + 10.0
|
||||
self.wAngleZ = self.wAngleZ + 5.0;
|
||||
|
||||
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
glColor3f(1.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glVertex3f(0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 1.0, 0.0);
|
||||
glVertex3f(0.5, -0.5, 0.5);
|
||||
|
||||
glColor3f(0.0, 1.0, 1.0);
|
||||
glVertex3f(0.5, 0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 1.0, 0.0);
|
||||
glVertex3f(0.5, -0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, -0.5);
|
||||
|
||||
glColor3f(1.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, 0.5);
|
||||
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(1.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glVertex3f(0.5, 0.5, 0.5);
|
||||
|
||||
glColor3f(0.0, 1.0, 1.0);
|
||||
glVertex3f(0.5, 0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 0.0, 1.0);
|
||||
glVertex3f(-0.5, 0.5, -0.5);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(1.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, 0.5);
|
||||
|
||||
glColor3f(1.0, 1.0, 0.0);
|
||||
glVertex3f(0.5, -0.5, 0.5);
|
||||
|
||||
glColor3f(0.0, 1.0, 0.0);
|
||||
glVertex3f(0.5, -0.5, -0.5);
|
||||
|
||||
glColor3f(0.0, 0.0, 0.0);
|
||||
glVertex3f(-0.5, -0.5, -0.5);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glFinish();
|
||||
SwapBuffers(wglGetCurrentDC());
|
||||
|
||||
self.busy = 0
|
||||
|
||||
def test():
|
||||
template = docview.DocTemplate(None, None, None, CubeView )
|
||||
# template = docview.DocTemplate(None, None, None, TestView )
|
||||
template.OpenDocumentFile(None)
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
|
@ -1,88 +0,0 @@
|
|||
#
|
||||
# Progress bar control example
|
||||
#
|
||||
# PyCProgressCtrl encapsulates the MFC CProgressCtrl class. To use it,
|
||||
# you:
|
||||
#
|
||||
# - Create the control with win32ui.CreateProgressCtrl()
|
||||
# - Create the control window with PyCProgressCtrl.CreateWindow()
|
||||
# - Initialize the range if you want it to be other than (0, 100) using
|
||||
# PyCProgressCtrl.SetRange()
|
||||
# - Either:
|
||||
# - Set the step size with PyCProgressCtrl.SetStep(), and
|
||||
# - Increment using PyCProgressCtrl.StepIt()
|
||||
# or:
|
||||
# - Set the amount completed using PyCProgressCtrl.SetPos()
|
||||
#
|
||||
# Example and progress bar code courtesy of KDL Technologies, Ltd., Hong Kong SAR, China.
|
||||
#
|
||||
|
||||
from pywin.mfc import dialog
|
||||
import win32ui
|
||||
import win32con
|
||||
|
||||
def MakeDlgTemplate():
|
||||
style = (win32con.DS_MODALFRAME |
|
||||
win32con.WS_POPUP |
|
||||
win32con.WS_VISIBLE |
|
||||
win32con.WS_CAPTION |
|
||||
win32con.WS_SYSMENU |
|
||||
win32con.DS_SETFONT)
|
||||
cs = (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE)
|
||||
|
||||
w = 215
|
||||
h = 36
|
||||
|
||||
dlg = [["Progress bar control example",
|
||||
(0, 0, w, h),
|
||||
style,
|
||||
None,
|
||||
(8, "MS Sans Serif")],
|
||||
]
|
||||
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
|
||||
dlg.append([128,
|
||||
"Tick",
|
||||
win32con.IDOK,
|
||||
(10, h - 18, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
|
||||
dlg.append([128,
|
||||
"Cancel",
|
||||
win32con.IDCANCEL,
|
||||
(w - 60, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON])
|
||||
|
||||
return dlg
|
||||
|
||||
class TestDialog(dialog.Dialog):
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.pbar = win32ui.CreateProgressCtrl()
|
||||
self.pbar.CreateWindow (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE,
|
||||
(10, 10, 310, 24),
|
||||
self, 1001)
|
||||
# self.pbar.SetStep (5)
|
||||
self.progress = 0
|
||||
self.pincr = 5
|
||||
return rc
|
||||
|
||||
def OnOK(self):
|
||||
# NB: StepIt wraps at the end if you increment past the upper limit!
|
||||
# self.pbar.StepIt()
|
||||
self.progress = self.progress + self.pincr
|
||||
if self.progress > 100:
|
||||
self.progress = 100
|
||||
if self.progress <= 100:
|
||||
self.pbar.SetPos(self.progress)
|
||||
|
||||
def demo(modal = 0):
|
||||
d = TestDialog (MakeDlgTemplate())
|
||||
if modal:
|
||||
d.DoModal()
|
||||
else:
|
||||
d.CreateWindow ()
|
||||
|
||||
if __name__=='__main__':
|
||||
demo(1)
|
|
@ -1,54 +0,0 @@
|
|||
# sliderdemo.py
|
||||
# Demo of the slider control courtesy of Mike Fletcher.
|
||||
|
||||
import win32con, win32ui
|
||||
from pywin.mfc import dialog
|
||||
|
||||
class MyDialog(dialog.Dialog):
|
||||
'''
|
||||
Example using simple controls
|
||||
'''
|
||||
_dialogstyle = (win32con.WS_MINIMIZEBOX | win32con.WS_DLGFRAME |
|
||||
win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE |
|
||||
win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT )
|
||||
_buttonstyle = (win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP |
|
||||
win32con.WS_CHILD | win32con.WS_VISIBLE)
|
||||
### The static template, contains all "normal" dialog items
|
||||
DIALOGTEMPLATE = [
|
||||
# the dialog itself is the first element in the template
|
||||
["Example slider", (0, 0, 50, 43), _dialogstyle, None, (8, "MS SansSerif")],
|
||||
# rest of elements are the controls within the dialog
|
||||
# standard "Close" button
|
||||
[128, "Close", win32con.IDCANCEL, (0, 30, 50, 13), _buttonstyle], ]
|
||||
### ID of the control to be created during dialog initialisation
|
||||
IDC_SLIDER = 9500
|
||||
def __init__(self ):
|
||||
dialog.Dialog.__init__(self, self.DIALOGTEMPLATE)
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
# now initialise your controls that you want to create
|
||||
# programmatically, including those which are OLE controls
|
||||
# those created directly by win32ui.Create*
|
||||
# and your "custom controls" which are subclasses/whatever
|
||||
win32ui.EnableControlContainer()
|
||||
self.slider = win32ui.CreateSliderCtrl( )
|
||||
self.slider.CreateWindow( win32con.WS_TABSTOP | win32con.WS_VISIBLE,
|
||||
(0,0,100,30),
|
||||
self._obj_,
|
||||
self.IDC_SLIDER)
|
||||
self.HookMessage(self.OnSliderMove, win32con.WM_HSCROLL)
|
||||
return rc
|
||||
|
||||
def OnSliderMove(self, params):
|
||||
print("Slider moved")
|
||||
|
||||
def OnCancel(self):
|
||||
print("The slider control is at position", self.slider.GetPos())
|
||||
self._obj_.OnCancel()
|
||||
###
|
||||
def demo():
|
||||
dia = MyDialog()
|
||||
dia.DoModal()
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo()
|
|
@ -1,72 +0,0 @@
|
|||
import win32ui
|
||||
import win32con
|
||||
import fontdemo
|
||||
from pywin.mfc import window, docview
|
||||
import commctrl
|
||||
|
||||
# derive from CMDIChild. This does much work for us.
|
||||
|
||||
class SplitterFrame(window.MDIChildWnd):
|
||||
def __init__(self):
|
||||
# call base CreateFrame
|
||||
self.images = None
|
||||
window.MDIChildWnd.__init__(self)
|
||||
|
||||
def OnCreateClient(self, cp, context):
|
||||
splitter = win32ui.CreateSplitter()
|
||||
doc = context.doc
|
||||
frame_rect = self.GetWindowRect()
|
||||
size = ((frame_rect[2] - frame_rect[0]),
|
||||
(frame_rect[3] - frame_rect[1])//2)
|
||||
sub_size = (size[0]//2, size[1])
|
||||
splitter.CreateStatic (self, 2, 1)
|
||||
self.v1 = win32ui.CreateEditView(doc)
|
||||
self.v2 = fontdemo.FontView(doc)
|
||||
# CListControl view
|
||||
self.v3 = win32ui.CreateListView(doc)
|
||||
sub_splitter = win32ui.CreateSplitter()
|
||||
# pass "splitter" so each view knows how to get to the others
|
||||
sub_splitter.CreateStatic (splitter, 1, 2)
|
||||
sub_splitter.CreateView(self.v1, 0, 0, (sub_size))
|
||||
sub_splitter.CreateView(self.v2, 0, 1, (0,0)) # size ignored.
|
||||
splitter.SetRowInfo(0, size[1] ,0)
|
||||
splitter.CreateView (self.v3, 1, 0, (0,0)) # size ignored.
|
||||
# Setup items in the imagelist
|
||||
self.images = win32ui.CreateImageList(32,32,1,5,5)
|
||||
self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_MAINFRAME))
|
||||
self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_PYTHONCONTYPE))
|
||||
self.images.Add(win32ui.GetApp().LoadIcon(win32ui.IDR_TEXTTYPE))
|
||||
self.v3.SetImageList(self.images, commctrl.LVSIL_NORMAL)
|
||||
self.v3.InsertItem(0, "Icon 1", 0)
|
||||
self.v3.InsertItem(0, "Icon 2", 1)
|
||||
self.v3.InsertItem(0, "Icon 3", 2)
|
||||
# self.v3.Arrange(commctrl.LVA_DEFAULT) Hmmm - win95 aligns left always???
|
||||
return 1
|
||||
def OnDestroy(self, msg):
|
||||
window.MDIChildWnd.OnDestroy(self, msg)
|
||||
if self.images:
|
||||
self.images.DeleteImageList()
|
||||
self.images = None
|
||||
|
||||
def InitialUpdateFrame(self, doc, makeVisible):
|
||||
self.v1.ReplaceSel("Hello from Edit Window 1")
|
||||
self.v1.SetModifiedFlag(0)
|
||||
|
||||
class SampleTemplate(docview.DocTemplate):
|
||||
def __init__(self):
|
||||
docview.DocTemplate.__init__(self, win32ui.IDR_PYTHONTYPE, None, SplitterFrame, None)
|
||||
def InitialUpdateFrame(self, frame, doc, makeVisible):
|
||||
# print "frame is ", frame, frame._obj_
|
||||
# print "doc is ", doc, doc._obj_
|
||||
self._obj_.InitialUpdateFrame(frame, doc, makeVisible) # call default handler.
|
||||
frame.InitialUpdateFrame(doc, makeVisible)
|
||||
|
||||
def demo():
|
||||
template = SampleTemplate()
|
||||
doc=template.OpenDocumentFile(None)
|
||||
doc.SetTitle("Splitter Demo")
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
demo()
|
|
@ -1,174 +0,0 @@
|
|||
# Demo of using just windows, without documents and views.
|
||||
|
||||
# Also demo of a GUI thread, pretty much direct from the MFC C++ sample MTMDI.
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import timer
|
||||
|
||||
from pywin.mfc import window, docview, thread
|
||||
from pywin.mfc.thread import WinThread
|
||||
|
||||
|
||||
WM_USER_PREPARE_TO_CLOSE = win32con.WM_USER + 32
|
||||
|
||||
# font is a dictionary in which the following elements matter:
|
||||
# (the best matching font to supplied parameters is returned)
|
||||
# name string name of the font as known by Windows
|
||||
# size point size of font in logical units
|
||||
# weight weight of font (win32con.FW_NORMAL, win32con.FW_BOLD)
|
||||
# italic boolean; true if set to anything but None
|
||||
# underline boolean; true if set to anything but None
|
||||
|
||||
# This window is a child window of a frame. It is not the frame window itself.
|
||||
class FontWindow(window.Wnd):
|
||||
def __init__(self, text = 'Python Rules!'):
|
||||
window.Wnd.__init__(self)
|
||||
self.text = text
|
||||
self.index = 0
|
||||
self.incr = 1
|
||||
self.width = self.height = 0
|
||||
self.ChangeAttributes()
|
||||
# set up message handlers
|
||||
|
||||
def Create(self, title, style, rect, parent):
|
||||
classStyle = win32con.CS_HREDRAW | win32con.CS_VREDRAW
|
||||
className = win32ui.RegisterWndClass(classStyle, 0, win32con.COLOR_WINDOW+1, 0)
|
||||
self._obj_ = win32ui.CreateWnd()
|
||||
self._obj_.AttachObject(self)
|
||||
self._obj_.CreateWindow(className, title, style, rect, parent, win32ui.AFX_IDW_PANE_FIRST)
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
self.HookMessage (self.OnPrepareToClose, WM_USER_PREPARE_TO_CLOSE)
|
||||
self.HookMessage (self.OnDestroy, win32con.WM_DESTROY)
|
||||
self.timerid = timer.set_timer (100, self.OnTimer)
|
||||
self.InvalidateRect()
|
||||
|
||||
def OnDestroy (self, msg):
|
||||
timer.kill_timer(self.timerid)
|
||||
|
||||
def OnTimer(self, id, timeVal):
|
||||
self.index = self.index + self.incr
|
||||
if self.index > len(self.text):
|
||||
self.incr = -1
|
||||
self.index = len(self.text)
|
||||
elif self.index < 0:
|
||||
self.incr = 1
|
||||
self.index = 0
|
||||
self.InvalidateRect()
|
||||
|
||||
def OnPaint (self):
|
||||
# print "Paint message from thread", win32api.GetCurrentThreadId()
|
||||
dc, paintStruct = self.BeginPaint()
|
||||
self.OnPrepareDC(dc, None)
|
||||
|
||||
if (self.width == 0 and self.height == 0):
|
||||
left, top, right, bottom = self.GetClientRect()
|
||||
self.width = right - left
|
||||
self.height = bottom - top
|
||||
x, y = self.width // 2, self.height // 2
|
||||
dc.TextOut (x, y, self.text[:self.index])
|
||||
self.EndPaint(paintStruct)
|
||||
|
||||
def ChangeAttributes(self):
|
||||
font_spec = {'name':'Arial', 'height':42}
|
||||
self.font = win32ui.CreateFont (font_spec)
|
||||
|
||||
def OnPrepareToClose(self, params):
|
||||
self.DestroyWindow()
|
||||
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
self.width = win32api.LOWORD(lParam)
|
||||
self.height = win32api.HIWORD(lParam)
|
||||
|
||||
def OnPrepareDC (self, dc, printinfo):
|
||||
# Set up the DC for forthcoming OnDraw call
|
||||
dc.SetTextColor (win32api.RGB(0,0,255))
|
||||
dc.SetBkColor (win32api.GetSysColor (win32con.COLOR_WINDOW))
|
||||
dc.SelectObject (self.font)
|
||||
dc.SetTextAlign (win32con.TA_CENTER | win32con.TA_BASELINE)
|
||||
|
||||
class FontFrame(window.MDIChildWnd):
|
||||
def __init__(self):
|
||||
pass # Dont call base class doc/view version...
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.AttachObject(self)
|
||||
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
rect = self.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
self.child = FontWindow("Not threaded")
|
||||
self.child.Create("FontDemo", win32con.WS_CHILD | win32con.WS_VISIBLE, rect, self)
|
||||
|
||||
|
||||
class TestThread(WinThread):
|
||||
def __init__(self, parentWindow):
|
||||
self.parentWindow = parentWindow
|
||||
self.child = None
|
||||
WinThread.__init__(self)
|
||||
def InitInstance(self):
|
||||
rect = self.parentWindow.GetClientRect()
|
||||
rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
|
||||
|
||||
self.child = FontWindow()
|
||||
self.child.Create("FontDemo", win32con.WS_CHILD | win32con.WS_VISIBLE, rect, self.parentWindow)
|
||||
self.SetMainFrame(self.child)
|
||||
return WinThread.InitInstance(self)
|
||||
|
||||
def ExitInstance(self):
|
||||
return 0
|
||||
|
||||
class ThreadedFontFrame(window.MDIChildWnd):
|
||||
def __init__(self):
|
||||
pass # Dont call base class doc/view version...
|
||||
self.thread = None
|
||||
def Create(self, title, rect = None, parent = None):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
|
||||
self._obj_ = win32ui.CreateMDIChild()
|
||||
self._obj_.CreateWindow(None, title, style, rect, parent)
|
||||
self._obj_.HookMessage(self.OnDestroy, win32con.WM_DESTROY)
|
||||
self._obj_.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
self.thread = TestThread(self)
|
||||
self.thread.CreateThread()
|
||||
|
||||
def OnSize(self, msg):
|
||||
pass
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
win32ui.OutputDebugString("OnDestroy\n")
|
||||
if self.thread and self.thread.child:
|
||||
child = self.thread.child
|
||||
child.SendMessage(WM_USER_PREPARE_TO_CLOSE, 0, 0)
|
||||
win32ui.OutputDebugString("Destroyed\n")
|
||||
|
||||
|
||||
def Demo():
|
||||
f = FontFrame()
|
||||
f.Create("Font Demo")
|
||||
|
||||
def ThreadedDemo():
|
||||
rect = win32ui.GetMainFrame().GetMDIClient().GetClientRect()
|
||||
rect = rect[0], int(rect[3]*3/4), int(rect[2]/4), rect[3]
|
||||
incr = rect[2]
|
||||
for i in range(4):
|
||||
if i==0:
|
||||
f = FontFrame()
|
||||
title = "Not threaded"
|
||||
else:
|
||||
f = ThreadedFontFrame()
|
||||
title = "Threaded GUI Demo"
|
||||
f.Create(title, rect)
|
||||
rect = rect[0] + incr, rect[1], rect[2]+incr, rect[3]
|
||||
# Givem a chance to start
|
||||
win32api.Sleep(100)
|
||||
win32ui.PumpWaitingMessages()
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
ThreadedDemo()
|
||||
# Demo()
|
|
@ -1,93 +0,0 @@
|
|||
# Demo of ToolBars
|
||||
|
||||
# Shows the toolbar control.
|
||||
# Demos how to make custom tooltips, etc.
|
||||
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
from pywin.mfc import docview, window, afxres
|
||||
import commctrl
|
||||
|
||||
class GenericFrame(window.MDIChildWnd):
|
||||
def OnCreateClient(self, cp, context):
|
||||
# handlers for toolbar buttons
|
||||
self.HookCommand (self.OnPrevious, 401)
|
||||
self.HookCommand (self.OnNext, 402)
|
||||
# Its not necessary for us to hook both of these - the
|
||||
# common controls should fall-back all by themselves.
|
||||
# Indeed, given we hook TTN_NEEDTEXTW, commctrl.TTN_NEEDTEXTA
|
||||
# will not be called.
|
||||
self.HookNotify(self.GetTTText, commctrl.TTN_NEEDTEXT)
|
||||
self.HookNotify(self.GetTTText, commctrl.TTN_NEEDTEXTW)
|
||||
|
||||
# parent = win32ui.GetMainFrame()
|
||||
parent = self
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | \
|
||||
afxres.CBRS_SIZE_DYNAMIC | afxres.CBRS_TOP | afxres.CBRS_TOOLTIPS | afxres.CBRS_FLYBY
|
||||
|
||||
buttons = (win32ui.ID_APP_ABOUT,win32ui.ID_VIEW_INTERACTIVE)
|
||||
bitmap = win32ui.IDB_BROWSER_HIER
|
||||
tbid = 0xE840
|
||||
self.toolbar = tb = win32ui.CreateToolBar (parent, style, tbid)
|
||||
tb.LoadBitmap(bitmap)
|
||||
tb.SetButtons(buttons)
|
||||
|
||||
tb.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
tb.SetWindowText("Test")
|
||||
parent.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
parent.DockControlBar(tb)
|
||||
parent.LoadBarState("ToolbarTest")
|
||||
window.MDIChildWnd.OnCreateClient(self, cp, context)
|
||||
return 1
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
self.SaveBarState("ToolbarTest")
|
||||
|
||||
def GetTTText(self, std, extra):
|
||||
(hwndFrom, idFrom, code) = std
|
||||
text, hinst, flags = extra
|
||||
if flags & commctrl.TTF_IDISHWND:
|
||||
return # Not handled
|
||||
if (idFrom==win32ui.ID_APP_ABOUT):
|
||||
# our 'extra' return value needs to be the following
|
||||
# entries from a NMTTDISPINFO[W] struct:
|
||||
# (szText, hinst, uFlags). None means 'don't change
|
||||
# the value'
|
||||
return 0, ("It works!", None, None)
|
||||
return None # not handled.
|
||||
|
||||
def GetMessageString(self, id):
|
||||
if id==win32ui.ID_APP_ABOUT:
|
||||
return "Dialog Test\nTest"
|
||||
else:
|
||||
return self._obj_.GetMessageString(id)
|
||||
|
||||
def OnSize (self, params):
|
||||
print('OnSize called with ', params)
|
||||
|
||||
def OnNext (self, id, cmd):
|
||||
print('OnNext called')
|
||||
|
||||
def OnPrevious (self, id, cmd):
|
||||
print('OnPrevious called')
|
||||
|
||||
msg = """\
|
||||
This toolbar was dynamically created.\r
|
||||
\r
|
||||
The first item's tooltips is provided by Python code.\r
|
||||
\r
|
||||
(Dont close the window with the toolbar in a floating state - it may not re-appear!)\r
|
||||
"""
|
||||
|
||||
def test():
|
||||
template = docview.DocTemplate( win32ui.IDR_PYTHONTYPE, None, GenericFrame, docview.EditView)
|
||||
doc = template.OpenDocumentFile(None)
|
||||
doc.SetTitle("Toolbar Test")
|
||||
view = doc.GetFirstView()
|
||||
view.SetWindowText(msg)
|
||||
|
||||
if __name__=='__main__':
|
||||
import demoutils
|
||||
if demoutils.NeedGoodGUI():
|
||||
test()
|
|
@ -1,10 +0,0 @@
|
|||
# is_platform_unicode is an old variable that was never correctly used and
|
||||
# is no longer referenced in pywin32. It is staying for a few releases incase
|
||||
# others are looking at it, but it will go away soon!
|
||||
is_platform_unicode = 0
|
||||
|
||||
# Ditto default_platform_encoding - not referenced and will die.
|
||||
default_platform_encoding = "mbcs"
|
||||
|
||||
# This one *is* real and used - but in practice can't be changed.
|
||||
default_scintilla_encoding = "utf-8" # Scintilla _only_ supports this ATM
|
|
@ -1,113 +0,0 @@
|
|||
import sys
|
||||
|
||||
# Some cruft to deal with the Pythonwin GUI booting up from a non GUI app.
|
||||
def _MakeDebuggerGUI():
|
||||
app.InitInstance()
|
||||
|
||||
isInprocApp = -1
|
||||
def _CheckNeedGUI():
|
||||
global isInprocApp
|
||||
if isInprocApp==-1:
|
||||
import win32ui
|
||||
isInprocApp = win32ui.GetApp().IsInproc()
|
||||
if isInprocApp:
|
||||
# MAY Need it - may already have one
|
||||
need = "pywin.debugger.dbgpyapp" not in sys.modules
|
||||
else:
|
||||
need = 0
|
||||
if need:
|
||||
import pywin.framework.app
|
||||
from . import dbgpyapp
|
||||
pywin.framework.app.CreateDefaultGUI(dbgpyapp.DebuggerPythonApp)
|
||||
|
||||
else:
|
||||
# Check we have the appropriate editor
|
||||
# No longer necessary!
|
||||
pass
|
||||
return need
|
||||
|
||||
# Inject some methods in the top level name-space.
|
||||
currentDebugger = None # Wipe out any old one on reload.
|
||||
|
||||
def _GetCurrentDebugger():
|
||||
global currentDebugger
|
||||
if currentDebugger is None:
|
||||
_CheckNeedGUI()
|
||||
from . import debugger
|
||||
currentDebugger = debugger.Debugger()
|
||||
return currentDebugger
|
||||
|
||||
def GetDebugger():
|
||||
# An error here is not nice - as we are probably trying to
|
||||
# break into the debugger on a Python error, any
|
||||
# error raised by this is usually silent, and causes
|
||||
# big problems later!
|
||||
try:
|
||||
rc = _GetCurrentDebugger()
|
||||
rc.GUICheckInit()
|
||||
return rc
|
||||
except:
|
||||
print("Could not create the debugger!")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def close():
|
||||
if currentDebugger is not None:
|
||||
currentDebugger.close()
|
||||
|
||||
def run(cmd,globals=None, locals=None, start_stepping = 1):
|
||||
_GetCurrentDebugger().run(cmd, globals,locals, start_stepping)
|
||||
|
||||
def runeval(expression, globals=None, locals=None):
|
||||
return _GetCurrentDebugger().runeval(expression, globals, locals)
|
||||
|
||||
def runcall(*args):
|
||||
return _GetCurrentDebugger().runcall(*args)
|
||||
|
||||
def set_trace():
|
||||
import sys
|
||||
d = _GetCurrentDebugger()
|
||||
|
||||
if d.frameShutdown: return # App closing
|
||||
|
||||
if d.stopframe != d.botframe:
|
||||
# If im not "running"
|
||||
return
|
||||
|
||||
sys.settrace(None) # May be hooked
|
||||
d.reset()
|
||||
d.set_trace()
|
||||
|
||||
# "brk" is an alias for "set_trace" ("break" is a reserved word :-(
|
||||
brk = set_trace
|
||||
|
||||
# Post-Mortem interface
|
||||
|
||||
def post_mortem(t=None):
|
||||
if t is None:
|
||||
t = sys.exc_info()[2] # Will be valid if we are called from an except handler.
|
||||
if t is None:
|
||||
try:
|
||||
t = sys.last_traceback
|
||||
except AttributeError:
|
||||
print("No traceback can be found from which to perform post-mortem debugging!")
|
||||
print("No debugging can continue")
|
||||
return
|
||||
p = _GetCurrentDebugger()
|
||||
if p.frameShutdown: return # App closing
|
||||
# No idea why I need to settrace to None - it should have been reset by now?
|
||||
sys.settrace(None)
|
||||
p.reset()
|
||||
while t.tb_next != None: t = t.tb_next
|
||||
p.bAtPostMortem = 1
|
||||
p.prep_run(None)
|
||||
try:
|
||||
p.interaction(t.tb_frame, t)
|
||||
finally:
|
||||
t = None
|
||||
p.bAtPostMortem = 0
|
||||
p.done_run()
|
||||
|
||||
def pm(t=None):
|
||||
post_mortem(t)
|
|
@ -1,31 +0,0 @@
|
|||
from . import dbgcon
|
||||
from pywin.mfc import dialog
|
||||
import win32ui
|
||||
|
||||
class DebuggerOptionsPropPage(dialog.PropertyPage):
|
||||
def __init__(self):
|
||||
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_DEBUGGER)
|
||||
|
||||
def OnInitDialog(self):
|
||||
options = self.options = dbgcon.LoadDebuggerOptions()
|
||||
self.AddDDX(win32ui.IDC_CHECK1, dbgcon.OPT_HIDE)
|
||||
self[dbgcon.OPT_STOP_EXCEPTIONS] = options[dbgcon.OPT_STOP_EXCEPTIONS]
|
||||
self.AddDDX(win32ui.IDC_CHECK2, dbgcon.OPT_STOP_EXCEPTIONS)
|
||||
self[dbgcon.OPT_HIDE] = options[dbgcon.OPT_HIDE]
|
||||
return dialog.PropertyPage.OnInitDialog(self)
|
||||
|
||||
def OnOK(self):
|
||||
self.UpdateData()
|
||||
dirty = 0
|
||||
for key, val in list(self.items()):
|
||||
if key in self.options:
|
||||
if self.options[key] != val:
|
||||
self.options[key] = val
|
||||
dirty = 1
|
||||
if dirty:
|
||||
dbgcon.SaveDebuggerOptions(self.options)
|
||||
# If there is a debugger open, then set its options.
|
||||
import pywin.debugger
|
||||
if pywin.debugger.currentDebugger is not None:
|
||||
pywin.debugger.currentDebugger.options = self.options
|
||||
return 1
|
|
@ -1,28 +0,0 @@
|
|||
# General constants for the debugger
|
||||
|
||||
DBGSTATE_NOT_DEBUGGING = 0
|
||||
DBGSTATE_RUNNING = 1
|
||||
DBGSTATE_BREAK = 2
|
||||
DBGSTATE_QUITTING = 3 # Attempting to back out of the debug session.
|
||||
|
||||
LINESTATE_CURRENT = 0x1 # This line is where we are stopped
|
||||
LINESTATE_BREAKPOINT = 0x2 # This line is a breakpoint
|
||||
LINESTATE_CALLSTACK = 0x4 # This line is in the callstack.
|
||||
|
||||
OPT_HIDE = 'hide'
|
||||
OPT_STOP_EXCEPTIONS = 'stopatexceptions'
|
||||
|
||||
import win32api, win32ui
|
||||
|
||||
def DoGetOption(optsDict, optName, default):
|
||||
optsDict[optName] = win32ui.GetProfileVal("Debugger Options", optName, default)
|
||||
|
||||
def LoadDebuggerOptions():
|
||||
opts = {}
|
||||
DoGetOption(opts, OPT_HIDE, 0)
|
||||
DoGetOption(opts, OPT_STOP_EXCEPTIONS, 1)
|
||||
return opts
|
||||
|
||||
def SaveDebuggerOptions(opts):
|
||||
for key, val in opts.items():
|
||||
win32ui.WriteProfileVal("Debugger Options", key, val)
|
|
@ -1,47 +0,0 @@
|
|||
# dbgpyapp.py - Debugger Python application class
|
||||
#
|
||||
import win32con
|
||||
import win32ui
|
||||
import sys
|
||||
import string
|
||||
import os
|
||||
from pywin.framework import intpyapp
|
||||
|
||||
version = '0.3.0'
|
||||
|
||||
class DebuggerPythonApp(intpyapp.InteractivePythonApp):
|
||||
def LoadMainFrame(self):
|
||||
" Create the main applications frame "
|
||||
self.frame = self.CreateMainFrame()
|
||||
self.SetMainFrame(self.frame)
|
||||
self.frame.LoadFrame(win32ui.IDR_DEBUGGER, win32con.WS_OVERLAPPEDWINDOW)
|
||||
self.frame.DragAcceptFiles() # we can accept these.
|
||||
self.frame.ShowWindow(win32con.SW_HIDE);
|
||||
self.frame.UpdateWindow();
|
||||
|
||||
# but we do rehook, hooking the new code objects.
|
||||
self.HookCommands()
|
||||
|
||||
def InitInstance(self):
|
||||
# Use a registry path of "Python\Pythonwin Debugger
|
||||
win32ui.SetAppName(win32ui.LoadString(win32ui.IDR_DEBUGGER))
|
||||
win32ui.SetRegistryKey("Python %s" % (sys.winver,))
|
||||
# We _need_ the Scintilla color editor.
|
||||
# (and we _always_ get it now :-)
|
||||
|
||||
numMRU = win32ui.GetProfileVal("Settings","Recent File List Size", 10)
|
||||
win32ui.LoadStdProfileSettings(numMRU)
|
||||
|
||||
self.LoadMainFrame()
|
||||
|
||||
# Display the interactive window if the user wants it.
|
||||
from pywin.framework import interact
|
||||
interact.CreateInteractiveWindowUserPreference()
|
||||
|
||||
# Load the modules we use internally.
|
||||
self.LoadSystemModules()
|
||||
# Load additional module the user may want.
|
||||
self.LoadUserModules()
|
||||
|
||||
# win32ui.CreateDebuggerThread()
|
||||
win32ui.EnableControlContainer()
|
|
@ -1,985 +0,0 @@
|
|||
# debugger.py
|
||||
|
||||
# A debugger for Pythonwin. Built from pdb.
|
||||
|
||||
# Mark Hammond (MHammond@skippinet.com.au) - Dec 94.
|
||||
|
||||
# usage:
|
||||
# >>> import pywin.debugger
|
||||
# >>> pywin.debugger.GetDebugger().run("command")
|
||||
|
||||
import pdb
|
||||
import bdb
|
||||
import sys
|
||||
import string
|
||||
import os
|
||||
import types
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
import pywin.docking.DockingBar
|
||||
from pywin.mfc import dialog, object, afxres, window
|
||||
from pywin.framework import app, interact, editor, scriptutils
|
||||
from pywin.framework.editor.color.coloreditor import MARKER_CURRENT, MARKER_BREAKPOINT
|
||||
from pywin.tools import browser, hierlist
|
||||
import commctrl
|
||||
import traceback
|
||||
|
||||
#import win32traceutil
|
||||
if win32ui.UNICODE:
|
||||
LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW
|
||||
else:
|
||||
LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITA
|
||||
|
||||
from .dbgcon import *
|
||||
|
||||
error = "pywin.debugger.error"
|
||||
|
||||
def SetInteractiveContext(globs, locs):
|
||||
if interact.edit is not None and interact.edit.currentView is not None:
|
||||
interact.edit.currentView.SetContext(globs, locs)
|
||||
|
||||
def _LineStateToMarker(ls):
|
||||
if ls==LINESTATE_CURRENT:
|
||||
return MARKER_CURRENT
|
||||
# elif ls == LINESTATE_CALLSTACK:
|
||||
# return MARKER_CALLSTACK
|
||||
return MARKER_BREAKPOINT
|
||||
|
||||
class HierListItem(browser.HLIPythonObject):
|
||||
pass
|
||||
|
||||
class HierFrameItem(HierListItem):
|
||||
def __init__(self, frame, debugger):
|
||||
HierListItem.__init__(self, frame, repr(frame))
|
||||
self.debugger = debugger
|
||||
def GetText(self):
|
||||
name = self.myobject.f_code.co_name
|
||||
if not name or name == '?' :
|
||||
# See if locals has a '__name__' (ie, a module)
|
||||
if '__name__' in self.myobject.f_locals:
|
||||
name = str(self.myobject.f_locals['__name__']) + " module"
|
||||
else:
|
||||
name = '<Debugger Context>'
|
||||
|
||||
return "%s (%s:%d)" % (name, os.path.split(self.myobject.f_code.co_filename)[1], self.myobject.f_lineno)
|
||||
def GetBitmapColumn(self):
|
||||
if self.debugger.curframe is self.myobject:
|
||||
return 7
|
||||
else:
|
||||
return 8
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
ret.append(HierFrameDict(self.myobject.f_locals, "Locals", 2))
|
||||
ret.append(HierFrameDict(self.myobject.f_globals, "Globals", 1))
|
||||
return ret
|
||||
def IsExpandable(self):
|
||||
return 1
|
||||
def TakeDefaultAction(self):
|
||||
# Set the default frame to be this frame.
|
||||
self.debugger.set_cur_frame(self.myobject)
|
||||
return 1
|
||||
|
||||
class HierFrameDict(browser.HLIDict):
|
||||
def __init__(self, dict, name, bitmapColumn):
|
||||
self.bitmapColumn=bitmapColumn
|
||||
browser.HLIDict.__init__(self, dict, name)
|
||||
def GetBitmapColumn(self):
|
||||
return self.bitmapColumn
|
||||
|
||||
class NoStackAvailableItem(HierListItem):
|
||||
def __init__(self, why):
|
||||
HierListItem.__init__(self, None, why)
|
||||
def IsExpandable(self):
|
||||
return 0
|
||||
def GetText(self):
|
||||
return self.name
|
||||
def GetBitmapColumn(self):
|
||||
return 8
|
||||
|
||||
class HierStackRoot(HierListItem):
|
||||
def __init__( self, debugger ):
|
||||
HierListItem.__init__(self, debugger, None)
|
||||
self.last_stack = []
|
||||
## def __del__(self):
|
||||
## print "HierStackRoot dieing"
|
||||
def GetSubList(self):
|
||||
debugger = self.myobject
|
||||
# print self.debugger.stack, self.debugger.curframe
|
||||
ret = []
|
||||
if debugger.debuggerState==DBGSTATE_BREAK:
|
||||
stackUse=debugger.stack[:]
|
||||
stackUse.reverse()
|
||||
self.last_stack = []
|
||||
for frame, lineno in stackUse:
|
||||
self.last_stack.append( (frame, lineno) )
|
||||
if frame is debugger.userbotframe: # Dont bother showing frames below our bottom frame.
|
||||
break
|
||||
for frame, lineno in self.last_stack:
|
||||
ret.append( HierFrameItem( frame, debugger ) )
|
||||
## elif debugger.debuggerState==DBGSTATE_NOT_DEBUGGING:
|
||||
## ret.append(NoStackAvailableItem('<nothing is being debugged>'))
|
||||
## else:
|
||||
## ret.append(NoStackAvailableItem('<stack not available while running>'))
|
||||
return ret
|
||||
def GetText(self):
|
||||
return 'root item'
|
||||
def IsExpandable(self):
|
||||
return 1
|
||||
|
||||
class HierListDebugger(hierlist.HierListWithItems):
|
||||
""" Hier List of stack frames, breakpoints, whatever """
|
||||
def __init__(self):
|
||||
hierlist.HierListWithItems.__init__(self, None, win32ui.IDB_DEBUGGER_HIER, None, win32api.RGB(255,0,0))
|
||||
def Setup(self, debugger):
|
||||
root = HierStackRoot(debugger)
|
||||
self.AcceptRoot(root)
|
||||
# def Refresh(self):
|
||||
# self.Setup()
|
||||
|
||||
class DebuggerWindow(window.Wnd):
|
||||
def __init__(self, ob):
|
||||
window.Wnd.__init__(self, ob)
|
||||
self.debugger = None
|
||||
|
||||
def Init(self, debugger):
|
||||
self.debugger = debugger
|
||||
|
||||
def GetDefRect(self):
|
||||
defRect = app.LoadWindowSize("Debugger Windows\\" + self.title)
|
||||
if defRect[2]-defRect[0]==0:
|
||||
defRect = 0, 0, 150, 150
|
||||
return defRect
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
newSize = self.GetWindowPlacement()[4]
|
||||
pywin.framework.app.SaveWindowSize("Debugger Windows\\" + self.title, newSize)
|
||||
return window.Wnd.OnDestroy(self, msg)
|
||||
|
||||
def OnKeyDown(self, msg):
|
||||
key = msg[2]
|
||||
if key in [13, 27, 32]: return 1
|
||||
if key in [46,8]: # delete/BS key
|
||||
self.DeleteSelected()
|
||||
return 0
|
||||
view = scriptutils.GetActiveView()
|
||||
try:
|
||||
firer = view.bindings.fire_key_event
|
||||
except AttributeError:
|
||||
firer = None
|
||||
if firer is not None:
|
||||
return firer(msg)
|
||||
else:
|
||||
return 1
|
||||
|
||||
def DeleteSelected(self):
|
||||
win32api.MessageBeep()
|
||||
|
||||
def EditSelected(self):
|
||||
win32api.MessageBeep()
|
||||
|
||||
class DebuggerStackWindow(DebuggerWindow):
|
||||
title = "Stack"
|
||||
def __init__(self):
|
||||
DebuggerWindow.__init__(self, win32ui.CreateTreeCtrl())
|
||||
self.list = HierListDebugger()
|
||||
self.listOK = 0
|
||||
def SaveState(self):
|
||||
self.list.DeleteAllItems()
|
||||
self.listOK = 0
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible())
|
||||
def CreateWindow(self, parent):
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS
|
||||
self._obj_.CreateWindow(style, self.GetDefRect(), parent, win32ui.IDC_LIST1)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN)
|
||||
self.list.HierInit (parent, self)
|
||||
self.listOK = 0 # delayed setup
|
||||
#self.list.Setup()
|
||||
|
||||
def RespondDebuggerState(self, state):
|
||||
assert self.debugger is not None, "Init not called"
|
||||
if not self.listOK:
|
||||
self.listOK = 1
|
||||
self.list.Setup(self.debugger)
|
||||
else:
|
||||
self.list.Refresh()
|
||||
|
||||
def RespondDebuggerData(self):
|
||||
try:
|
||||
handle = self.GetChildItem(0)
|
||||
except win32ui.error:
|
||||
return # No items
|
||||
while 1:
|
||||
item = self.list.ItemFromHandle(handle)
|
||||
col = self.list.GetBitmapColumn(item)
|
||||
selCol = self.list.GetSelectedBitmapColumn(item)
|
||||
if selCol is None: selCol = col
|
||||
if self.list.GetItemImage(handle)!= (col, selCol):
|
||||
self.list.SetItemImage(handle, col, selCol)
|
||||
try:
|
||||
handle = self.GetNextSiblingItem(handle)
|
||||
except win32ui.error:
|
||||
break
|
||||
|
||||
class DebuggerListViewWindow(DebuggerWindow):
|
||||
def __init__(self):
|
||||
DebuggerWindow.__init__(self, win32ui.CreateListCtrl())
|
||||
def CreateWindow(self, parent):
|
||||
list = self
|
||||
style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | commctrl.LVS_EDITLABELS | commctrl.LVS_REPORT
|
||||
self._obj_.CreateWindow(style, self.GetDefRect(), parent, win32ui.IDC_LIST1)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)
|
||||
self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN)
|
||||
list = self
|
||||
title, width = self.columns[0]
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, width, title, 0)
|
||||
list.InsertColumn(0, itemDetails)
|
||||
col = 1
|
||||
for title, width in self.columns[1:]:
|
||||
col = col + 1
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, width, title, 0)
|
||||
list.InsertColumn(col, itemDetails)
|
||||
parent.HookNotify(self.OnListEndLabelEdit, LVN_ENDLABELEDIT)
|
||||
parent.HookNotify(self.OnItemRightClick, commctrl.NM_RCLICK)
|
||||
parent.HookNotify(self.OnItemDoubleClick, commctrl.NM_DBLCLK)
|
||||
|
||||
def RespondDebuggerData(self):
|
||||
pass
|
||||
|
||||
def RespondDebuggerState(self, state):
|
||||
pass
|
||||
|
||||
def EditSelected(self):
|
||||
try:
|
||||
sel = self.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
except win32ui.error:
|
||||
return
|
||||
self.EditLabel(sel)
|
||||
|
||||
def OnKeyDown(self, msg):
|
||||
key = msg[2]
|
||||
# If someone starts typing, they probably are trying to edit the text!
|
||||
if chr(key) in string.ascii_uppercase:
|
||||
self.EditSelected()
|
||||
return 0
|
||||
return DebuggerWindow.OnKeyDown(self, msg)
|
||||
|
||||
def OnItemDoubleClick(self, notify_data, extra):
|
||||
self.EditSelected()
|
||||
|
||||
def OnItemRightClick(self, notify_data, extra):
|
||||
# First select the item we right-clicked on.
|
||||
pt = self.ScreenToClient(win32api.GetCursorPos())
|
||||
flags, hItem, subitem = self.HitTest(pt)
|
||||
if hItem==-1 or commctrl.TVHT_ONITEM & flags==0:
|
||||
return None
|
||||
self.SetItemState(hItem, commctrl.LVIS_SELECTED, commctrl.LVIS_SELECTED)
|
||||
|
||||
menu = win32ui.CreatePopupMenu()
|
||||
menu.AppendMenu(win32con.MF_STRING|win32con.MF_ENABLED,1000, "Edit item")
|
||||
menu.AppendMenu(win32con.MF_STRING|win32con.MF_ENABLED,1001, "Delete item")
|
||||
dockbar = self.GetParent()
|
||||
if dockbar.IsFloating():
|
||||
hook_parent = win32ui.GetMainFrame()
|
||||
else:
|
||||
hook_parent = self.GetParentFrame()
|
||||
hook_parent.HookCommand(self.OnEditItem, 1000)
|
||||
hook_parent.HookCommand(self.OnDeleteItem, 1001)
|
||||
menu.TrackPopupMenu(win32api.GetCursorPos()) # track at mouse position.
|
||||
return None
|
||||
|
||||
def OnDeleteItem(self,command, code):
|
||||
self.DeleteSelected()
|
||||
def OnEditItem(self, command, code):
|
||||
self.EditSelected()
|
||||
|
||||
class DebuggerBreakpointsWindow(DebuggerListViewWindow):
|
||||
title = "Breakpoints"
|
||||
columns = [ ("Condition", 70), ("Location", 1024)]
|
||||
|
||||
def SaveState(self):
|
||||
items = []
|
||||
for i in range(self.GetItemCount()):
|
||||
items.append(self.GetItemText(i,0))
|
||||
items.append(self.GetItemText(i,1))
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "BreakpointList", "\t".join(items))
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible())
|
||||
return 1
|
||||
|
||||
def OnListEndLabelEdit(self, std, extra):
|
||||
item = extra[0]
|
||||
text = item[4]
|
||||
if text is None: return
|
||||
|
||||
item_id = self.GetItem(item[0])[6]
|
||||
|
||||
from bdb import Breakpoint
|
||||
for bplist in Breakpoint.bplist.values():
|
||||
for bp in bplist:
|
||||
if id(bp)==item_id:
|
||||
if text.strip().lower()=="none":
|
||||
text = None
|
||||
bp.cond = text
|
||||
break
|
||||
self.RespondDebuggerData()
|
||||
|
||||
def DeleteSelected(self):
|
||||
try:
|
||||
num = self.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
item_id = self.GetItem(num)[6]
|
||||
from bdb import Breakpoint
|
||||
for bplist in list(Breakpoint.bplist.values()):
|
||||
for bp in bplist:
|
||||
if id(bp)==item_id:
|
||||
self.debugger.clear_break(bp.file, bp.line)
|
||||
break
|
||||
except win32ui.error:
|
||||
win32api.MessageBeep()
|
||||
self.RespondDebuggerData()
|
||||
|
||||
def RespondDebuggerData(self):
|
||||
l = self
|
||||
l.DeleteAllItems()
|
||||
index = -1
|
||||
from bdb import Breakpoint
|
||||
for bplist in Breakpoint.bplist.values():
|
||||
for bp in bplist:
|
||||
baseName = os.path.split(bp.file)[1]
|
||||
cond = bp.cond
|
||||
item = index+1, 0, 0, 0, str(cond), 0, id(bp)
|
||||
index = l.InsertItem(item)
|
||||
l.SetItemText(index, 1, "%s: %s" % (baseName, bp.line))
|
||||
|
||||
class DebuggerWatchWindow(DebuggerListViewWindow):
|
||||
title = "Watch"
|
||||
columns = [ ("Expression", 70), ("Value", 1024)]
|
||||
|
||||
def CreateWindow(self, parent):
|
||||
DebuggerListViewWindow.CreateWindow(self, parent)
|
||||
items = win32ui.GetProfileVal("Debugger Windows\\" + self.title, "Items", "").split("\t")
|
||||
index = -1
|
||||
for item in items:
|
||||
if item:
|
||||
index = self.InsertItem(index+1, item)
|
||||
self.InsertItem(index+1, "<New Item>")
|
||||
|
||||
def SaveState(self):
|
||||
items = []
|
||||
for i in range(self.GetItemCount()-1):
|
||||
items.append(self.GetItemText(i,0))
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "Items", "\t".join(items))
|
||||
win32ui.WriteProfileVal("Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible())
|
||||
return 1
|
||||
|
||||
def OnListEndLabelEdit(self, std, extra):
|
||||
item = extra[0]
|
||||
itemno = item[0]
|
||||
text = item[4]
|
||||
if text is None: return
|
||||
self.SetItemText(itemno, 0, text)
|
||||
if itemno == self.GetItemCount()-1:
|
||||
self.InsertItem(itemno+1, "<New Item>")
|
||||
self.RespondDebuggerState(self.debugger.debuggerState)
|
||||
|
||||
def DeleteSelected(self):
|
||||
try:
|
||||
num = self.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
||||
if num < self.GetItemCount()-1: # We cant delete the last
|
||||
self.DeleteItem(num)
|
||||
except win32ui.error:
|
||||
win32api.MessageBeep()
|
||||
|
||||
def RespondDebuggerState(self, state):
|
||||
globs = locs = None
|
||||
if state==DBGSTATE_BREAK:
|
||||
if self.debugger.curframe:
|
||||
globs = self.debugger.curframe.f_globals
|
||||
locs = self.debugger.curframe.f_locals
|
||||
elif state==DBGSTATE_NOT_DEBUGGING:
|
||||
import __main__
|
||||
globs = locs = __main__.__dict__
|
||||
for i in range(self.GetItemCount()-1):
|
||||
text = self.GetItemText(i, 0)
|
||||
if globs is None:
|
||||
val = ""
|
||||
else:
|
||||
try:
|
||||
val = repr( eval( text, globs, locs) )
|
||||
except SyntaxError:
|
||||
val = "Syntax Error"
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
val = traceback.format_exception_only(t, v)[0].strip()
|
||||
tb = None # prevent a cycle.
|
||||
self.SetItemText(i, 1, val)
|
||||
|
||||
def CreateDebuggerDialog(parent, klass):
|
||||
control = klass()
|
||||
control.CreateWindow(parent)
|
||||
return control
|
||||
|
||||
DebuggerDialogInfos = (
|
||||
(0xe810, DebuggerStackWindow, None),
|
||||
(0xe811, DebuggerBreakpointsWindow, (10, 10)),
|
||||
(0xe812, DebuggerWatchWindow, None),
|
||||
)
|
||||
|
||||
# Prepare all the "control bars" for this package.
|
||||
# If control bars are not all loaded when the toolbar-state functions are
|
||||
# called, things go horribly wrong.
|
||||
def PrepareControlBars(frame):
|
||||
style = win32con.WS_CHILD | afxres.CBRS_SIZE_DYNAMIC | afxres.CBRS_TOP | afxres.CBRS_TOOLTIPS | afxres.CBRS_FLYBY
|
||||
tbd = win32ui.CreateToolBar (frame, style, win32ui.ID_VIEW_TOOLBAR_DBG)
|
||||
tbd.ModifyStyle(0, commctrl.TBSTYLE_FLAT)
|
||||
tbd.LoadToolBar(win32ui.IDR_DEBUGGER)
|
||||
tbd.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
tbd.SetWindowText("Debugger")
|
||||
frame.DockControlBar(tbd)
|
||||
|
||||
# and the other windows.
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
try:
|
||||
frame.GetControlBar(id)
|
||||
exists=1
|
||||
except win32ui.error:
|
||||
exists=0
|
||||
if exists: continue
|
||||
bar = pywin.docking.DockingBar.DockingBar()
|
||||
style=win32con.WS_CHILD | afxres.CBRS_LEFT # don't create visible.
|
||||
bar.CreateWindow(frame, CreateDebuggerDialog, klass.title, id, style, childCreatorArgs=(klass,))
|
||||
bar.SetBarStyle( bar.GetBarStyle()|afxres.CBRS_TOOLTIPS|afxres.CBRS_FLYBY|afxres.CBRS_SIZE_DYNAMIC)
|
||||
bar.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
if float is None:
|
||||
frame.DockControlBar(bar)
|
||||
else:
|
||||
frame.FloatControlBar(bar, float, afxres.CBRS_ALIGN_ANY)
|
||||
|
||||
## frame.ShowControlBar(bar, 0, 1)
|
||||
|
||||
|
||||
SKIP_NONE=0
|
||||
SKIP_STEP=1
|
||||
SKIP_RUN=2
|
||||
|
||||
debugger_parent=pdb.Pdb
|
||||
class Debugger(debugger_parent):
|
||||
def __init__(self):
|
||||
self.inited = 0
|
||||
self.skipBotFrame = SKIP_NONE
|
||||
self.userbotframe = None
|
||||
self.frameShutdown = 0
|
||||
self.pumping = 0
|
||||
self.debuggerState = DBGSTATE_NOT_DEBUGGING # Assume so, anyway.
|
||||
self.shownLineCurrent = None # The last filename I highlighted.
|
||||
self.shownLineCallstack = None # The last filename I highlighted.
|
||||
self.last_cmd_debugged = ""
|
||||
self.abortClosed = 0
|
||||
self.isInitialBreakpoint = 0
|
||||
debugger_parent.__init__(self)
|
||||
|
||||
# See if any break-points have been set in the editor
|
||||
for doc in editor.editorTemplate.GetDocumentList():
|
||||
lineNo = -1
|
||||
while 1:
|
||||
lineNo = doc.MarkerGetNext(lineNo+1, MARKER_BREAKPOINT)
|
||||
if lineNo <= 0: break
|
||||
self.set_break(doc.GetPathName(), lineNo)
|
||||
|
||||
self.reset()
|
||||
self.inForcedGUI = win32ui.GetApp().IsInproc()
|
||||
self.options = LoadDebuggerOptions()
|
||||
self.bAtException = self.bAtPostMortem = 0
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
def close(self, frameShutdown = 0):
|
||||
# abortClose indicates if we have total shutdown
|
||||
# (ie, main window is dieing)
|
||||
if self.pumping:
|
||||
# Can stop pump here, as it only posts a message, and
|
||||
# returns immediately.
|
||||
if not self.StopDebuggerPump(): # User cancelled close.
|
||||
return 0
|
||||
# NOTE - from this point on the close can not be
|
||||
# stopped - the WM_QUIT message is already in the queue.
|
||||
self.frameShutdown = frameShutdown
|
||||
if not self.inited: return 1
|
||||
self.inited = 0
|
||||
|
||||
SetInteractiveContext(None, None)
|
||||
|
||||
frame = win32ui.GetMainFrame()
|
||||
# Hide the debuger toolbars (as they wont normally form part of the main toolbar state.
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
try:
|
||||
tb = frame.GetControlBar(id)
|
||||
if tb.dialog is not None: # We may never have actually been shown.
|
||||
tb.dialog.SaveState()
|
||||
frame.ShowControlBar(tb, 0, 1)
|
||||
except win32ui.error:
|
||||
pass
|
||||
|
||||
self._UnshowCurrentLine()
|
||||
self.set_quit()
|
||||
return 1
|
||||
|
||||
def StopDebuggerPump(self):
|
||||
assert self.pumping, "Can't stop the debugger pump if Im not pumping!"
|
||||
# After stopping a pump, I may never return.
|
||||
if self.GUIAboutToFinishInteract():
|
||||
self.pumping = 0
|
||||
win32ui.StopDebuggerPump() # Posts a message, so we do return.
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def get_option(self, option):
|
||||
"""Public interface into debugger options
|
||||
"""
|
||||
try:
|
||||
return self.options[option]
|
||||
except KeyError:
|
||||
raise error("Option %s is not a valid option" % option)
|
||||
|
||||
def prep_run(self, cmd):
|
||||
pass
|
||||
def done_run(self, cmd=None):
|
||||
self.RespondDebuggerState(DBGSTATE_NOT_DEBUGGING)
|
||||
self.close()
|
||||
def canonic(self, fname):
|
||||
return os.path.abspath(fname).lower()
|
||||
def reset(self):
|
||||
debugger_parent.reset(self)
|
||||
self.userbotframe = None
|
||||
self.UpdateAllLineStates()
|
||||
self._UnshowCurrentLine()
|
||||
|
||||
|
||||
def setup(self, f, t):
|
||||
debugger_parent.setup(self, f, t)
|
||||
self.bAtException = t is not None
|
||||
|
||||
def set_break(self, filename, lineno, temporary=0, cond = None):
|
||||
filename = self.canonic(filename)
|
||||
self.SetLineState(filename, lineno, LINESTATE_BREAKPOINT)
|
||||
return debugger_parent.set_break(self, filename, lineno, temporary, cond)
|
||||
|
||||
def clear_break(self, filename, lineno):
|
||||
filename = self.canonic(filename)
|
||||
self.ResetLineState(filename, lineno, LINESTATE_BREAKPOINT)
|
||||
return debugger_parent.clear_break(self, filename, lineno)
|
||||
|
||||
def cmdloop(self):
|
||||
if self.frameShutdown: return # App in the process of closing - never break in!
|
||||
self.GUIAboutToBreak()
|
||||
|
||||
def print_stack_entry(self, frame):
|
||||
# We dont want a stack printed - our GUI is better :-)
|
||||
pass
|
||||
|
||||
def user_return(self, frame, return_value):
|
||||
# Same as parent, just no "print"
|
||||
# This function is called when a return trap is set here
|
||||
frame.f_locals['__return__'] = return_value
|
||||
self.interaction(frame, None)
|
||||
|
||||
def user_call(self, frame, args):
|
||||
# base class has an annoying 'print' that adds no value to us...
|
||||
if self.stop_here(frame):
|
||||
self.interaction(frame, None)
|
||||
|
||||
def user_exception(self, frame, exc_info):
|
||||
# This function is called if an exception occurs,
|
||||
# but only if we are to stop at or just below this level
|
||||
(exc_type, exc_value, exc_traceback) = exc_info
|
||||
if self.get_option(OPT_STOP_EXCEPTIONS):
|
||||
frame.f_locals['__exception__'] = exc_type, exc_value
|
||||
print("Unhandled exception while debugging...")
|
||||
# on both py2k and py3k, we may be called with exc_value
|
||||
# being the args to the exception, or it may already be
|
||||
# instantiated (IOW, PyErr_Normalize() hasn't been
|
||||
# called on the args). In py2k this is fine, but in
|
||||
# py3k, traceback.print_exception fails. So on py3k
|
||||
# we instantiate an exception instance to print.
|
||||
if sys.version_info > (3,) and not isinstance(exc_value, BaseException):
|
||||
# they are args - may be a single item or already a tuple
|
||||
if not isinstance(exc_value, tuple):
|
||||
exc_value = (exc_value,)
|
||||
exc_value = exc_type(*exc_value)
|
||||
|
||||
traceback.print_exception(exc_type, exc_value, exc_traceback)
|
||||
self.interaction(frame, exc_traceback)
|
||||
|
||||
def user_line(self, frame):
|
||||
if frame.f_lineno==0: return
|
||||
debugger_parent.user_line(self, frame)
|
||||
|
||||
def stop_here(self, frame):
|
||||
if self.isInitialBreakpoint:
|
||||
self.isInitialBreakpoint = 0
|
||||
self.set_continue()
|
||||
return 0
|
||||
if frame is self.botframe and self.skipBotFrame == SKIP_RUN:
|
||||
self.set_continue()
|
||||
return 0
|
||||
if frame is self.botframe and self.skipBotFrame == SKIP_STEP:
|
||||
self.set_step()
|
||||
return 0
|
||||
return debugger_parent.stop_here(self, frame)
|
||||
|
||||
def run(self, cmd,globals=None, locals=None, start_stepping = 1):
|
||||
if not isinstance(cmd, (str, types.CodeType)):
|
||||
raise TypeError("Only strings can be run")
|
||||
self.last_cmd_debugged = cmd
|
||||
if start_stepping:
|
||||
self.isInitialBreakpoint = 0
|
||||
else:
|
||||
self.isInitialBreakpoint = 1
|
||||
try:
|
||||
if globals is None:
|
||||
import __main__
|
||||
globals = __main__.__dict__
|
||||
if locals is None:
|
||||
locals = globals
|
||||
self.reset()
|
||||
self.prep_run(cmd)
|
||||
sys.settrace(self.trace_dispatch)
|
||||
if type(cmd) != types.CodeType:
|
||||
cmd = cmd+'\n'
|
||||
try:
|
||||
try:
|
||||
if start_stepping: self.skipBotFrame = SKIP_STEP
|
||||
else: self.skipBotFrame = SKIP_RUN
|
||||
exec(cmd, globals, locals)
|
||||
except bdb.BdbQuit:
|
||||
pass
|
||||
finally:
|
||||
self.skipBotFrame = SKIP_NONE
|
||||
self.quitting = 1
|
||||
sys.settrace(None)
|
||||
|
||||
finally:
|
||||
self.done_run(cmd)
|
||||
|
||||
def runeval(self, expr, globals=None, locals=None):
|
||||
self.prep_run(expr)
|
||||
try:
|
||||
debugger_parent.runeval(self, expr, globals, locals)
|
||||
finally:
|
||||
self.done_run(expr)
|
||||
|
||||
def runexec(self, what, globs=None, locs=None):
|
||||
self.reset()
|
||||
sys.settrace(self.trace_dispatch)
|
||||
try:
|
||||
try:
|
||||
exec(what, globs, locs)
|
||||
except bdb.BdbQuit:
|
||||
pass
|
||||
finally:
|
||||
self.quitting = 1
|
||||
sys.settrace(None)
|
||||
|
||||
def do_set_step(self):
|
||||
if self.GUIAboutToRun():
|
||||
self.set_step()
|
||||
|
||||
def do_set_next(self):
|
||||
if self.GUIAboutToRun():
|
||||
self.set_next(self.curframe)
|
||||
|
||||
def do_set_return(self):
|
||||
if self.GUIAboutToRun():
|
||||
self.set_return(self.curframe)
|
||||
|
||||
def do_set_continue(self):
|
||||
if self.GUIAboutToRun():
|
||||
self.set_continue()
|
||||
|
||||
def set_quit(self):
|
||||
ok = 1
|
||||
if self.pumping:
|
||||
ok = self.StopDebuggerPump()
|
||||
if ok:
|
||||
debugger_parent.set_quit(self)
|
||||
|
||||
def _dump_frame_(self, frame,name=None):
|
||||
if name is None: name = ""
|
||||
if frame:
|
||||
if frame.f_code and frame.f_code.co_filename:
|
||||
fname = os.path.split(frame.f_code.co_filename)[1]
|
||||
else:
|
||||
fname = "??"
|
||||
print(repr(name), fname, frame.f_lineno, frame)
|
||||
else:
|
||||
print(repr(name), "None")
|
||||
|
||||
def set_trace(self):
|
||||
# Start debugging from _2_ levels up!
|
||||
try:
|
||||
1 + ''
|
||||
except:
|
||||
frame = sys.exc_info()[2].tb_frame.f_back.f_back
|
||||
self.reset()
|
||||
self.userbotframe = None
|
||||
while frame:
|
||||
# scriptutils.py creates a local variable with name
|
||||
# '_debugger_stop_frame_', and we dont go past it
|
||||
# (everything above this is Pythonwin framework code)
|
||||
if "_debugger_stop_frame_" in frame.f_locals:
|
||||
self.userbotframe = frame
|
||||
break
|
||||
|
||||
frame.f_trace = self.trace_dispatch
|
||||
self.botframe = frame
|
||||
frame = frame.f_back
|
||||
self.set_step()
|
||||
sys.settrace(self.trace_dispatch)
|
||||
|
||||
def set_cur_frame(self, frame):
|
||||
# Sets the "current" frame - ie, the frame with focus. This is the
|
||||
# frame on which "step out" etc actions are taken.
|
||||
# This may or may not be the top of the stack.
|
||||
assert frame is not None, "You must pass a valid frame"
|
||||
self.curframe = frame
|
||||
for f, index in self.stack:
|
||||
if f is frame:
|
||||
self.curindex = index
|
||||
break
|
||||
else:
|
||||
assert 0, "Can't find the frame in the stack."
|
||||
SetInteractiveContext(frame.f_globals, frame.f_locals)
|
||||
self.GUIRespondDebuggerData()
|
||||
self.ShowCurrentLine()
|
||||
|
||||
def IsBreak(self):
|
||||
return self.debuggerState == DBGSTATE_BREAK
|
||||
|
||||
def IsDebugging(self):
|
||||
return self.debuggerState != DBGSTATE_NOT_DEBUGGING
|
||||
|
||||
def RespondDebuggerState(self, state):
|
||||
if state == self.debuggerState: return
|
||||
if state==DBGSTATE_NOT_DEBUGGING: # Debugger exists, but not doing anything
|
||||
title = ""
|
||||
elif state==DBGSTATE_RUNNING: # Code is running under the debugger.
|
||||
title = " - running"
|
||||
elif state==DBGSTATE_BREAK: # We are at a breakpoint or stepping or whatever.
|
||||
if self.bAtException:
|
||||
if self.bAtPostMortem:
|
||||
title = " - post mortem exception"
|
||||
else:
|
||||
title = " - exception"
|
||||
else:
|
||||
title = " - break"
|
||||
else:
|
||||
raise error("Invalid debugger state passed!")
|
||||
win32ui.GetMainFrame().SetWindowText(win32ui.LoadString(win32ui.IDR_MAINFRAME) + title)
|
||||
if self.debuggerState == DBGSTATE_QUITTING and state != DBGSTATE_NOT_DEBUGGING:
|
||||
print("Ignoring state change cos Im trying to stop!", state)
|
||||
return
|
||||
self.debuggerState = state
|
||||
try:
|
||||
frame = win32ui.GetMainFrame()
|
||||
except win32ui.error:
|
||||
frame = None
|
||||
if frame is not None:
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
cb = win32ui.GetMainFrame().GetControlBar(id).dialog
|
||||
cb.RespondDebuggerState(state)
|
||||
# Tell each open editor window about the state transition
|
||||
for doc in editor.editorTemplate.GetDocumentList():
|
||||
doc.OnDebuggerStateChange(state)
|
||||
self.ShowCurrentLine()
|
||||
|
||||
#
|
||||
# GUI debugger interface.
|
||||
#
|
||||
def GUICheckInit(self):
|
||||
if self.inited: return
|
||||
self.inited = 1
|
||||
frame = win32ui.GetMainFrame()
|
||||
|
||||
# Ensure the debugger windows are attached to the debugger.
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
w = frame.GetControlBar(id)
|
||||
w.dialog.Init(self)
|
||||
# Show toolbar if it was visible during last debug session
|
||||
# This would be better done using a CDockState, but that class is not wrapped yet
|
||||
if win32ui.GetProfileVal("Debugger Windows\\" + w.dialog.title, "Visible", 0):
|
||||
frame.ShowControlBar(w, 1, 1)
|
||||
|
||||
# ALWAYS show debugging toolbar, regardless of saved state
|
||||
tb = frame.GetControlBar(win32ui.ID_VIEW_TOOLBAR_DBG)
|
||||
frame.ShowControlBar(tb, 1, 1)
|
||||
self.GUIRespondDebuggerData()
|
||||
|
||||
# frame.RecalcLayout()
|
||||
|
||||
def GetDebuggerBar(self, barName):
|
||||
frame = win32ui.GetMainFrame()
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
if klass.title == barName:
|
||||
return frame.GetControlBar(id)
|
||||
assert 0, "Can't find a bar of that name!"
|
||||
|
||||
def GUIRespondDebuggerData(self):
|
||||
if not self.inited: # GUI not inited - no toolbars etc.
|
||||
return
|
||||
|
||||
for id, klass, float in DebuggerDialogInfos:
|
||||
cb = win32ui.GetMainFrame().GetControlBar(id).dialog
|
||||
cb.RespondDebuggerData()
|
||||
|
||||
def GUIAboutToRun(self):
|
||||
if not self.StopDebuggerPump():
|
||||
return 0
|
||||
self._UnshowCurrentLine()
|
||||
self.RespondDebuggerState(DBGSTATE_RUNNING)
|
||||
SetInteractiveContext(None, None)
|
||||
return 1
|
||||
|
||||
def GUIAboutToBreak(self):
|
||||
"Called as the GUI debugger is about to get context, and take control of the running program."
|
||||
self.GUICheckInit()
|
||||
self.RespondDebuggerState(DBGSTATE_BREAK)
|
||||
self.GUIAboutToInteract()
|
||||
if self.pumping:
|
||||
print("!!! Already pumping - outa here")
|
||||
return
|
||||
self.pumping = 1
|
||||
win32ui.StartDebuggerPump() # NOTE - This will NOT return until the user is finished interacting
|
||||
assert not self.pumping, "Should not be pumping once the pump has finished"
|
||||
if self.frameShutdown: # User shut down app while debugging
|
||||
win32ui.GetMainFrame().PostMessage(win32con.WM_CLOSE)
|
||||
|
||||
def GUIAboutToInteract(self):
|
||||
"Called as the GUI is about to perform any interaction with the user"
|
||||
frame = win32ui.GetMainFrame()
|
||||
# Remember the enabled state of our main frame
|
||||
# may be disabled primarily if a modal dialog is displayed.
|
||||
# Only get at enabled via GetWindowLong.
|
||||
self.bFrameEnabled = frame.IsWindowEnabled()
|
||||
self.oldForeground = None
|
||||
fw = win32ui.GetForegroundWindow()
|
||||
if fw is not frame:
|
||||
self.oldForeground = fw
|
||||
# fw.EnableWindow(0) Leave enabled for now?
|
||||
self.oldFrameEnableState = frame.IsWindowEnabled()
|
||||
frame.EnableWindow(1)
|
||||
if self.inForcedGUI and not frame.IsWindowVisible():
|
||||
frame.ShowWindow(win32con.SW_SHOW)
|
||||
frame.UpdateWindow()
|
||||
if self.curframe:
|
||||
SetInteractiveContext(self.curframe.f_globals, self.curframe.f_locals)
|
||||
else:
|
||||
SetInteractiveContext(None, None)
|
||||
self.GUIRespondDebuggerData()
|
||||
|
||||
def GUIAboutToFinishInteract(self):
|
||||
"""Called as the GUI is about to finish any interaction with the user
|
||||
Returns non zero if we are allowed to stop interacting"""
|
||||
if self.oldForeground is not None:
|
||||
try:
|
||||
win32ui.GetMainFrame().EnableWindow(self.oldFrameEnableState)
|
||||
self.oldForeground.EnableWindow(1)
|
||||
except win32ui.error:
|
||||
# old window may be dead.
|
||||
pass
|
||||
# self.oldForeground.SetForegroundWindow() - fails??
|
||||
if not self.inForcedGUI:
|
||||
return 1 # Never a problem, and nothing else to do.
|
||||
# If we are running a forced GUI, we may never get an opportunity
|
||||
# to interact again. Therefore we perform a "SaveAll", to makesure that
|
||||
# any documents are saved before leaving.
|
||||
for template in win32ui.GetApp().GetDocTemplateList():
|
||||
for doc in template.GetDocumentList():
|
||||
if not doc.SaveModified():
|
||||
return 0
|
||||
# All documents saved - now hide the app and debugger.
|
||||
if self.get_option(OPT_HIDE):
|
||||
frame = win32ui.GetMainFrame()
|
||||
frame.ShowWindow(win32con.SW_HIDE)
|
||||
return 1
|
||||
|
||||
#
|
||||
# Pythonwin interface - all stuff to do with showing source files,
|
||||
# changing line states etc.
|
||||
#
|
||||
def ShowLineState(self, fileName, lineNo, lineState):
|
||||
# Set the state of a line, open if not already
|
||||
self.ShowLineNo(fileName, lineNo)
|
||||
self.SetLineState(fileName, lineNo, lineState)
|
||||
|
||||
def SetLineState(self, fileName, lineNo, lineState):
|
||||
# Set the state of a line if the document is open.
|
||||
doc = editor.editorTemplate.FindOpenDocument(fileName)
|
||||
if doc is not None:
|
||||
marker = _LineStateToMarker(lineState)
|
||||
if not doc.MarkerCheck(lineNo, marker):
|
||||
doc.MarkerAdd(lineNo, marker)
|
||||
|
||||
def ResetLineState(self, fileName, lineNo, lineState):
|
||||
# Set the state of a line if the document is open.
|
||||
doc = editor.editorTemplate.FindOpenDocument(fileName)
|
||||
if doc is not None:
|
||||
marker = _LineStateToMarker(lineState)
|
||||
doc.MarkerDelete(lineNo, marker)
|
||||
|
||||
def UpdateDocumentLineStates(self, doc):
|
||||
# Show all lines in their special status color. If the doc is open
|
||||
# all line states are reset.
|
||||
doc.MarkerDeleteAll( MARKER_BREAKPOINT )
|
||||
doc.MarkerDeleteAll( MARKER_CURRENT )
|
||||
fname = self.canonic(doc.GetPathName())
|
||||
# Now loop over all break-points
|
||||
for line in self.breaks.get(fname, []):
|
||||
doc.MarkerAdd(line, MARKER_BREAKPOINT)
|
||||
# And the current line if in this document.
|
||||
if self.shownLineCurrent and fname == self.shownLineCurrent[0]:
|
||||
lineNo = self.shownLineCurrent[1]
|
||||
if not doc.MarkerCheck(lineNo, MARKER_CURRENT):
|
||||
doc.MarkerAdd(lineNo, MARKER_CURRENT)
|
||||
# if self.shownLineCallstack and fname == self.shownLineCallstack[0]:
|
||||
# doc.MarkerAdd(self.shownLineCallstack[1], MARKER_CURRENT)
|
||||
|
||||
def UpdateAllLineStates(self):
|
||||
for doc in editor.editorTemplate.GetDocumentList():
|
||||
self.UpdateDocumentLineStates(doc)
|
||||
|
||||
def ShowCurrentLine(self):
|
||||
# Show the current line. Only ever 1 current line - undoes last current
|
||||
# The "Current Line" is self.curframe.
|
||||
# The "Callstack Line" is the top of the stack.
|
||||
# If current == callstack, only show as current.
|
||||
self._UnshowCurrentLine() # un-highlight the old one.
|
||||
if self.curframe:
|
||||
fileName = self.canonic(self.curframe.f_code.co_filename)
|
||||
lineNo = self.curframe.f_lineno
|
||||
self.shownLineCurrent = fileName, lineNo
|
||||
self.ShowLineState(fileName, lineNo, LINESTATE_CURRENT)
|
||||
|
||||
def _UnshowCurrentLine(self):
|
||||
"Unshow the current line, and forget it"
|
||||
if self.shownLineCurrent is not None:
|
||||
fname, lineno = self.shownLineCurrent
|
||||
self.ResetLineState(fname, lineno, LINESTATE_CURRENT)
|
||||
self.shownLineCurrent = None
|
||||
|
||||
def ShowLineNo( self, filename, lineno ):
|
||||
wasOpen = editor.editorTemplate.FindOpenDocument(filename) is not None
|
||||
if os.path.isfile(filename) and scriptutils.JumpToDocument(filename, lineno):
|
||||
if not wasOpen:
|
||||
doc = editor.editorTemplate.FindOpenDocument(filename)
|
||||
if doc is not None:
|
||||
self.UpdateDocumentLineStates(doc)
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
else:
|
||||
# Can't find the source file - linecache may have it?
|
||||
import linecache
|
||||
line = linecache.getline(filename, lineno)
|
||||
print("%s(%d): %s" % (os.path.basename(filename), lineno, line[:-1].expandtabs(4)))
|
||||
return 0
|
|
@ -1,48 +0,0 @@
|
|||
# NOTE NOTE - This module is designed to fail!
|
||||
#
|
||||
# The ONLY purpose for this script is testing/demoing the
|
||||
# Pythonwin debugger package.
|
||||
|
||||
# It does nothing useful, and it even doesnt do that!
|
||||
|
||||
import pywin.debugger, sys, time
|
||||
import traceback
|
||||
|
||||
def a():
|
||||
a=1
|
||||
try:
|
||||
b()
|
||||
except:
|
||||
# Break into the debugger with the exception information.
|
||||
pywin.debugger.post_mortem(sys.exc_info()[2])
|
||||
a=1
|
||||
a=2
|
||||
a=3
|
||||
a=4
|
||||
pass
|
||||
|
||||
def b():
|
||||
b=1
|
||||
pywin.debugger.set_trace()
|
||||
# After importing or running this module, you are likely to be
|
||||
# sitting at the next line. This is because we explicitely
|
||||
# broke into the debugger using the "set_trace() function
|
||||
# "pywin.debugger.brk()" is a shorter alias for this.
|
||||
c()
|
||||
pass
|
||||
|
||||
def c():
|
||||
c=1
|
||||
d()
|
||||
|
||||
def d():
|
||||
d=1
|
||||
e(d)
|
||||
raise ValueError("Hi")
|
||||
|
||||
def e(arg):
|
||||
e=1
|
||||
time.sleep(1)
|
||||
return e
|
||||
|
||||
a()
|
|
@ -1,116 +0,0 @@
|
|||
# The property page to define generic IDE options for Pythonwin
|
||||
|
||||
from pywin.mfc import dialog
|
||||
from pywin.framework import interact
|
||||
import win32ui
|
||||
import win32con
|
||||
|
||||
buttonControlMap = {
|
||||
win32ui.IDC_BUTTON1: win32ui.IDC_EDIT1,
|
||||
win32ui.IDC_BUTTON2: win32ui.IDC_EDIT2,
|
||||
win32ui.IDC_BUTTON3: win32ui.IDC_EDIT3,
|
||||
}
|
||||
|
||||
class OptionsPropPage(dialog.PropertyPage):
|
||||
def __init__(self):
|
||||
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_IDE)
|
||||
self.AddDDX(win32ui.IDC_CHECK1, "bShowAtStartup")
|
||||
self.AddDDX(win32ui.IDC_CHECK2, "bDocking")
|
||||
self.AddDDX(win32ui.IDC_EDIT4, 'MRUSize', "i")
|
||||
|
||||
def OnInitDialog(self):
|
||||
|
||||
edit = self.GetDlgItem(win32ui.IDC_EDIT1)
|
||||
format = eval(win32ui.GetProfileVal(interact.sectionProfile, interact.STYLE_INTERACTIVE_PROMPT, str(interact.formatInput)))
|
||||
edit.SetDefaultCharFormat(format)
|
||||
edit.SetWindowText("Input Text")
|
||||
|
||||
edit = self.GetDlgItem(win32ui.IDC_EDIT2)
|
||||
format = eval(win32ui.GetProfileVal(interact.sectionProfile, interact.STYLE_INTERACTIVE_OUTPUT, str(interact.formatOutput)))
|
||||
edit.SetDefaultCharFormat(format)
|
||||
edit.SetWindowText("Output Text")
|
||||
|
||||
edit = self.GetDlgItem(win32ui.IDC_EDIT3)
|
||||
format = eval(win32ui.GetProfileVal(interact.sectionProfile, interact.STYLE_INTERACTIVE_ERROR, str(interact.formatOutputError)))
|
||||
edit.SetDefaultCharFormat(format)
|
||||
edit.SetWindowText("Error Text")
|
||||
|
||||
self['bShowAtStartup'] = interact.LoadPreference("Show at startup", 1)
|
||||
self['bDocking'] = interact.LoadPreference("Docking", 0)
|
||||
self['MRUSize'] = win32ui.GetProfileVal("Settings","Recent File List Size", 10)
|
||||
|
||||
# Hook the button clicks.
|
||||
self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON1)
|
||||
self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON2)
|
||||
self.HookCommand(self.HandleCharFormatChange, win32ui.IDC_BUTTON3)
|
||||
|
||||
# Ensure the spin control remains in range.
|
||||
spinner = self.GetDlgItem(win32ui.IDC_SPIN1)
|
||||
spinner.SetRange(1, 16)
|
||||
|
||||
return dialog.PropertyPage.OnInitDialog(self)
|
||||
|
||||
# Called to save away the new format tuple for the specified item.
|
||||
def HandleCharFormatChange(self, id, code):
|
||||
if code == win32con.BN_CLICKED:
|
||||
editId = buttonControlMap.get(id)
|
||||
assert editId is not None, "Format button has no associated edit control"
|
||||
editControl = self.GetDlgItem(editId)
|
||||
existingFormat = editControl.GetDefaultCharFormat()
|
||||
flags = win32con.CF_SCREENFONTS
|
||||
d=win32ui.CreateFontDialog(existingFormat, flags, None, self)
|
||||
if d.DoModal()==win32con.IDOK:
|
||||
cf = d.GetCharFormat()
|
||||
editControl.SetDefaultCharFormat(cf)
|
||||
self.SetModified(1)
|
||||
return 0 # We handled this fully!
|
||||
|
||||
def OnOK(self):
|
||||
# Handle the edit controls - get all the fonts, put them back into interact, then
|
||||
# get interact to save its stuff!
|
||||
controlAttrs = [
|
||||
(win32ui.IDC_EDIT1, interact.STYLE_INTERACTIVE_PROMPT),
|
||||
(win32ui.IDC_EDIT2, interact.STYLE_INTERACTIVE_OUTPUT),
|
||||
(win32ui.IDC_EDIT3, interact.STYLE_INTERACTIVE_ERROR)]
|
||||
for id, key in controlAttrs:
|
||||
control = self.GetDlgItem(id)
|
||||
fmt = control.GetDefaultCharFormat()
|
||||
win32ui.WriteProfileVal(interact.sectionProfile, key, str(fmt))
|
||||
|
||||
# Save the other interactive window options.
|
||||
interact.SavePreference("Show at startup", self['bShowAtStartup'])
|
||||
interact.SavePreference("Docking", self['bDocking'])
|
||||
|
||||
# And the other options.
|
||||
win32ui.WriteProfileVal("Settings","Recent File List Size", self['MRUSize'])
|
||||
|
||||
return 1
|
||||
def ChangeFormat(self, fmtAttribute, fmt):
|
||||
dlg = win32ui.CreateFontDialog(fmt)
|
||||
if dlg.DoModal() != win32con.IDOK: return None
|
||||
return dlg.GetCharFormat()
|
||||
|
||||
def OnFormatTitle(self, command, code):
|
||||
fmt = self.GetFormat(interact.formatTitle)
|
||||
if fmt:
|
||||
formatTitle = fmt
|
||||
SaveFontPreferences()
|
||||
|
||||
def OnFormatInput(self, command, code):
|
||||
global formatInput
|
||||
fmt = self.GetFormat(formatInput)
|
||||
if fmt:
|
||||
formatInput = fmt
|
||||
SaveFontPreferences()
|
||||
def OnFormatOutput(self, command, code):
|
||||
global formatOutput
|
||||
fmt = self.GetFormat(formatOutput)
|
||||
if fmt:
|
||||
formatOutput = fmt
|
||||
SaveFontPreferences()
|
||||
def OnFormatError(self, command, code):
|
||||
global formatOutputError
|
||||
fmt = self.GetFormat(formatOutputError)
|
||||
if fmt:
|
||||
formatOutputError = fmt
|
||||
SaveFontPreferences()
|
|
@ -1,122 +0,0 @@
|
|||
from pywin.mfc import dialog
|
||||
import win32ui, win32con, commctrl, win32api
|
||||
|
||||
class ListDialog (dialog.Dialog):
|
||||
|
||||
def __init__ (self, title, list):
|
||||
dialog.Dialog.__init__ (self, self._maketemplate(title))
|
||||
self.HookMessage (self.on_size, win32con.WM_SIZE)
|
||||
self.HookNotify(self.OnListItemChange, commctrl.LVN_ITEMCHANGED)
|
||||
self.HookCommand(self.OnListClick, win32ui.IDC_LIST1)
|
||||
self.items = list
|
||||
|
||||
def _maketemplate(self, title):
|
||||
style = win32con.WS_DLGFRAME | win32con.WS_SYSMENU | win32con.WS_VISIBLE
|
||||
ls = (
|
||||
win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE |
|
||||
commctrl.LVS_ALIGNLEFT |
|
||||
commctrl.LVS_REPORT
|
||||
)
|
||||
bs = (
|
||||
win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE
|
||||
)
|
||||
return [ [title, (0, 0, 200, 200), style, None, (8, "MS Sans Serif")],
|
||||
["SysListView32", None, win32ui.IDC_LIST1, (0, 0, 200, 200), ls],
|
||||
[128, "OK", win32con.IDOK, (10, 0, 50, 14), bs | win32con.BS_DEFPUSHBUTTON],
|
||||
[128, "Cancel",win32con.IDCANCEL,(0, 0, 50, 14), bs],
|
||||
]
|
||||
|
||||
def FillList(self):
|
||||
size = self.GetWindowRect()
|
||||
width = size[2] - size[0] - (10)
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, width, "Item", 0)
|
||||
self.itemsControl.InsertColumn(0, itemDetails)
|
||||
index = 0
|
||||
for item in self.items:
|
||||
index = self.itemsControl.InsertItem(index+1, str(item), 0)
|
||||
|
||||
def OnListClick(self, id, code):
|
||||
if code==commctrl.NM_DBLCLK:
|
||||
self.EndDialog(win32con.IDOK)
|
||||
return 1
|
||||
|
||||
def OnListItemChange(self,std, extra):
|
||||
(hwndFrom, idFrom, code), (itemNotify, sub, newState, oldState, change, point, lparam) = std, extra
|
||||
oldSel = (oldState & commctrl.LVIS_SELECTED)!=0
|
||||
newSel = (newState & commctrl.LVIS_SELECTED)!=0
|
||||
if oldSel != newSel:
|
||||
try:
|
||||
self.selecteditem = itemNotify
|
||||
self.butOK.EnableWindow(1)
|
||||
except win32ui.error:
|
||||
self.selecteditem = None
|
||||
|
||||
|
||||
def OnInitDialog (self):
|
||||
rc = dialog.Dialog.OnInitDialog (self)
|
||||
self.itemsControl = self.GetDlgItem(win32ui.IDC_LIST1)
|
||||
self.butOK = self.GetDlgItem(win32con.IDOK)
|
||||
self.butCancel = self.GetDlgItem(win32con.IDCANCEL)
|
||||
|
||||
self.FillList()
|
||||
|
||||
size = self.GetWindowRect()
|
||||
self.LayoutControls(size[2]-size[0], size[3]-size[1])
|
||||
self.butOK.EnableWindow(0) # wait for first selection
|
||||
return rc
|
||||
|
||||
def LayoutControls(self, w, h):
|
||||
self.itemsControl.MoveWindow((0,0,w,h-30))
|
||||
self.butCancel.MoveWindow((10, h-24, 60, h-4))
|
||||
self.butOK.MoveWindow((w-60, h-24, w-10, h-4))
|
||||
|
||||
def on_size (self, params):
|
||||
lparam = params[3]
|
||||
w = win32api.LOWORD(lparam)
|
||||
h = win32api.HIWORD(lparam)
|
||||
self.LayoutControls(w, h)
|
||||
|
||||
class ListsDialog(ListDialog):
|
||||
def __init__(self, title, list, colHeadings = ['Item']):
|
||||
ListDialog.__init__(self, title, list)
|
||||
self.colHeadings = colHeadings
|
||||
|
||||
def FillList(self):
|
||||
index = 0
|
||||
size = self.GetWindowRect()
|
||||
width = size[2] - size[0] - (10) - win32api.GetSystemMetrics(win32con.SM_CXVSCROLL)
|
||||
numCols = len(self.colHeadings)
|
||||
|
||||
for col in self.colHeadings:
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, width/numCols, col, 0)
|
||||
self.itemsControl.InsertColumn(index, itemDetails)
|
||||
index = index + 1
|
||||
index = 0
|
||||
for items in self.items:
|
||||
index = self.itemsControl.InsertItem(index+1, str(items[0]), 0)
|
||||
for itemno in range(1,numCols):
|
||||
item = items[itemno]
|
||||
self.itemsControl.SetItemText(index, itemno, str(item))
|
||||
|
||||
def SelectFromList (title, lst):
|
||||
dlg = ListDialog(title, lst)
|
||||
if dlg.DoModal()==win32con.IDOK:
|
||||
return dlg.selecteditem
|
||||
else:
|
||||
return None
|
||||
|
||||
def SelectFromLists (title, lists, headings):
|
||||
dlg = ListsDialog(title, lists, headings)
|
||||
if dlg.DoModal()==win32con.IDOK:
|
||||
return dlg.selecteditem
|
||||
else:
|
||||
return None
|
||||
|
||||
def test():
|
||||
# print SelectFromList('Single list', [1,2,3])
|
||||
print(SelectFromLists('Multi-List', [ ('1',1, 'a'), ('2',2, 'b'), ('3',3, 'c' )], ['Col 1', 'Col 2']))
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
|
@ -1,121 +0,0 @@
|
|||
'''login -- PythonWin user ID and password dialog box
|
||||
|
||||
(Adapted from originally distributed with Mark Hammond's PythonWin -
|
||||
this now replaces it!)
|
||||
|
||||
login.GetLogin() displays a modal "OK/Cancel" dialog box with input
|
||||
fields for a user ID and password. The password field input is masked
|
||||
with *'s. GetLogin takes two optional parameters, a window title, and a
|
||||
default user ID. If these parameters are omitted, the title defaults to
|
||||
"Login", and the user ID is left blank. GetLogin returns a (userid, password)
|
||||
tuple. GetLogin can be called from scripts running on the console - i.e. you
|
||||
don't need to write a full-blown GUI app to use it.
|
||||
|
||||
login.GetPassword() is similar, except there is no username field.
|
||||
|
||||
Example:
|
||||
import pywin.dialogs.login
|
||||
title = "FTP Login"
|
||||
def_user = "fred"
|
||||
userid, password = pywin.dialogs.login.GetLogin(title, def_user)
|
||||
|
||||
Jim Eggleston, 28 August 1996
|
||||
Merged with dlgpass and moved to pywin.dialogs by Mark Hammond Jan 1998.
|
||||
'''
|
||||
|
||||
import win32ui
|
||||
import win32api
|
||||
import win32con
|
||||
from pywin.mfc import dialog
|
||||
|
||||
def MakeLoginDlgTemplate(title):
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
|
||||
# Window frame and title
|
||||
dlg = [ [title, (0, 0, 184, 40), style, None, (8, "MS Sans Serif")], ]
|
||||
|
||||
# ID label and text box
|
||||
dlg.append([130, "User ID:", -1, (7, 9, 69, 9), cs | win32con.SS_LEFT])
|
||||
s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER
|
||||
dlg.append(['EDIT', None, win32ui.IDC_EDIT1, (50, 7, 60, 12), s])
|
||||
|
||||
# Password label and text box
|
||||
dlg.append([130, "Password:", -1, (7, 22, 69, 9), cs | win32con.SS_LEFT])
|
||||
s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER
|
||||
dlg.append(['EDIT', None, win32ui.IDC_EDIT2, (50, 20, 60, 12), s | win32con.ES_PASSWORD])
|
||||
|
||||
# OK/Cancel Buttons
|
||||
s = cs | win32con.WS_TABSTOP
|
||||
dlg.append([128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
s = win32con.BS_PUSHBUTTON | s
|
||||
dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 20, 50, 14), s])
|
||||
return dlg
|
||||
|
||||
def MakePasswordDlgTemplate(title):
|
||||
style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
|
||||
cs = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
# Window frame and title
|
||||
dlg = [ [title, (0, 0, 177, 45), style, None, (8, "MS Sans Serif")], ]
|
||||
|
||||
# Password label and text box
|
||||
dlg.append([130, "Password:", -1, (7, 7, 69, 9), cs | win32con.SS_LEFT])
|
||||
s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER
|
||||
dlg.append(['EDIT', None, win32ui.IDC_EDIT1, (50, 7, 60, 12), s | win32con.ES_PASSWORD])
|
||||
|
||||
# OK/Cancel Buttons
|
||||
s = cs | win32con.WS_TABSTOP | win32con.BS_PUSHBUTTON
|
||||
dlg.append([128, "OK", win32con.IDOK, (124, 5, 50, 14), s | win32con.BS_DEFPUSHBUTTON])
|
||||
dlg.append([128, "Cancel", win32con.IDCANCEL, (124, 22, 50, 14), s])
|
||||
return dlg
|
||||
|
||||
class LoginDlg(dialog.Dialog):
|
||||
Cancel = 0
|
||||
def __init__(self, title):
|
||||
dialog.Dialog.__init__(self, MakeLoginDlgTemplate(title) )
|
||||
self.AddDDX(win32ui.IDC_EDIT1,'userid')
|
||||
self.AddDDX(win32ui.IDC_EDIT2,'password')
|
||||
|
||||
def GetLogin(title='Login', userid='', password=''):
|
||||
d = LoginDlg(title)
|
||||
d['userid'] = userid
|
||||
d['password'] = password
|
||||
if d.DoModal() != win32con.IDOK:
|
||||
return (None, None)
|
||||
else:
|
||||
return (d['userid'], d['password'])
|
||||
|
||||
class PasswordDlg(dialog.Dialog):
|
||||
def __init__(self, title):
|
||||
dialog.Dialog.__init__(self, MakePasswordDlgTemplate(title) )
|
||||
self.AddDDX(win32ui.IDC_EDIT1,'password')
|
||||
|
||||
def GetPassword(title='Password', password=''):
|
||||
d = PasswordDlg(title)
|
||||
d['password'] = password
|
||||
if d.DoModal()!=win32con.IDOK:
|
||||
return None
|
||||
return d['password']
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
title = 'Login'
|
||||
def_user = ''
|
||||
if len(sys.argv) > 1:
|
||||
title = sys.argv[1]
|
||||
if len(sys.argv) > 2:
|
||||
def_userid = sys.argv[2]
|
||||
userid, password = GetLogin(title, def_user)
|
||||
if userid == password == None:
|
||||
print("User pressed Cancel")
|
||||
else:
|
||||
print("User ID: ", userid)
|
||||
print("Password:", password)
|
||||
newpassword = GetPassword("Reenter just for fun", password)
|
||||
if newpassword is None:
|
||||
print("User cancelled")
|
||||
else:
|
||||
what = ""
|
||||
if newpassword != password:
|
||||
what = "not "
|
||||
print("The passwords did %smatch" % (what))
|
|
@ -1,227 +0,0 @@
|
|||
# No cancel button.
|
||||
|
||||
from pywin.mfc import dialog
|
||||
from pywin.mfc.thread import WinThread
|
||||
import threading
|
||||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import time
|
||||
|
||||
def MakeProgressDlgTemplate(caption, staticText = ""):
|
||||
style = (win32con.DS_MODALFRAME |
|
||||
win32con.WS_POPUP |
|
||||
win32con.WS_VISIBLE |
|
||||
win32con.WS_CAPTION |
|
||||
win32con.WS_SYSMENU |
|
||||
win32con.DS_SETFONT)
|
||||
cs = (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE)
|
||||
|
||||
w = 215
|
||||
h = 36 # With button
|
||||
h = 40
|
||||
|
||||
dlg = [[caption,
|
||||
(0, 0, w, h),
|
||||
style,
|
||||
None,
|
||||
(8, "MS Sans Serif")],
|
||||
]
|
||||
|
||||
s = win32con.WS_TABSTOP | cs
|
||||
|
||||
dlg.append([130, staticText, 1000, (7, 7, w-7, h-32), cs | win32con.SS_LEFT])
|
||||
|
||||
# dlg.append([128,
|
||||
# "Cancel",
|
||||
# win32con.IDCANCEL,
|
||||
# (w - 60, h - 18, 50, 14), s | win32con.BS_PUSHBUTTON])
|
||||
|
||||
return dlg
|
||||
|
||||
class CStatusProgressDialog(dialog.Dialog):
|
||||
def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
|
||||
self.initMsg = msg
|
||||
templ = MakeProgressDlgTemplate(title, msg)
|
||||
dialog.Dialog.__init__(self, templ)
|
||||
self.maxticks = maxticks
|
||||
self.tickincr = tickincr
|
||||
self.pbar = None
|
||||
|
||||
def OnInitDialog(self):
|
||||
rc = dialog.Dialog.OnInitDialog(self)
|
||||
self.static = self.GetDlgItem(1000)
|
||||
self.pbar = win32ui.CreateProgressCtrl()
|
||||
self.pbar.CreateWindow (win32con.WS_CHILD |
|
||||
win32con.WS_VISIBLE,
|
||||
(10, 30, 310, 44),
|
||||
self, 1001)
|
||||
self.pbar.SetRange(0, self.maxticks)
|
||||
self.pbar.SetStep(self.tickincr)
|
||||
self.progress = 0
|
||||
self.pincr = 5
|
||||
return rc
|
||||
|
||||
def Close(self):
|
||||
self.EndDialog(0)
|
||||
|
||||
def SetMaxTicks(self, maxticks):
|
||||
if self.pbar is not None:
|
||||
self.pbar.SetRange(0, maxticks)
|
||||
|
||||
def Tick(self):
|
||||
if self.pbar is not None:
|
||||
self.pbar.StepIt()
|
||||
|
||||
def SetTitle(self, text):
|
||||
self.SetWindowText(text)
|
||||
|
||||
def SetText(self, text):
|
||||
self.SetDlgItemText(1000, text)
|
||||
|
||||
def Set(self, pos, max = None):
|
||||
if self.pbar is not None:
|
||||
self.pbar.SetPos(pos)
|
||||
if max is not None:
|
||||
self.pbar.SetRange(0, max)
|
||||
|
||||
# a progress dialog created in a new thread - especially suitable for
|
||||
# console apps with no message loop.
|
||||
MYWM_SETTITLE = win32con.WM_USER+10
|
||||
MYWM_SETMSG = win32con.WM_USER+11
|
||||
MYWM_TICK = win32con.WM_USER+12
|
||||
MYWM_SETMAXTICKS = win32con.WM_USER+13
|
||||
MYWM_SET = win32con.WM_USER+14
|
||||
|
||||
class CThreadedStatusProcessDialog(CStatusProgressDialog):
|
||||
def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
|
||||
self.title = title
|
||||
self.msg = msg
|
||||
self.threadid = win32api.GetCurrentThreadId()
|
||||
CStatusProgressDialog.__init__(self, title, msg, maxticks, tickincr)
|
||||
|
||||
def OnInitDialog(self):
|
||||
rc = CStatusProgressDialog.OnInitDialog(self)
|
||||
self.HookMessage(self.OnTitle, MYWM_SETTITLE)
|
||||
self.HookMessage(self.OnMsg, MYWM_SETMSG)
|
||||
self.HookMessage(self.OnTick, MYWM_TICK)
|
||||
self.HookMessage(self.OnMaxTicks, MYWM_SETMAXTICKS)
|
||||
self.HookMessage(self.OnSet, MYWM_SET)
|
||||
return rc
|
||||
|
||||
def _Send(self, msg):
|
||||
try:
|
||||
self.PostMessage(msg)
|
||||
except win32ui.error:
|
||||
# the user closed the window - but this does not cancel the
|
||||
# process - so just ignore it.
|
||||
pass
|
||||
|
||||
def OnTitle(self, msg):
|
||||
CStatusProgressDialog.SetTitle(self, self.title)
|
||||
|
||||
def OnMsg(self, msg):
|
||||
CStatusProgressDialog.SetText(self, self.msg)
|
||||
|
||||
def OnTick(self, msg):
|
||||
CStatusProgressDialog.Tick(self)
|
||||
|
||||
def OnMaxTicks(self, msg):
|
||||
CStatusProgressDialog.SetMaxTicks(self, self.maxticks)
|
||||
|
||||
def OnSet(self, msg):
|
||||
CStatusProgressDialog.Set(self, self.pos, self.max)
|
||||
|
||||
def Close(self):
|
||||
assert self.threadid, "No thread!"
|
||||
win32api.PostThreadMessage(self.threadid, win32con.WM_QUIT, 0, 0)
|
||||
|
||||
def SetMaxTicks(self, maxticks):
|
||||
self.maxticks = maxticks
|
||||
self._Send(MYWM_SETMAXTICKS)
|
||||
def SetTitle(self, title):
|
||||
self.title = title
|
||||
self._Send(MYWM_SETTITLE)
|
||||
def SetText(self, text):
|
||||
self.msg = text
|
||||
self._Send(MYWM_SETMSG)
|
||||
def Tick(self):
|
||||
self._Send(MYWM_TICK)
|
||||
def Set(self, pos, max = None):
|
||||
self.pos = pos
|
||||
self.max = max
|
||||
self._Send(MYWM_SET)
|
||||
|
||||
class ProgressThread(WinThread):
|
||||
def __init__(self, title, msg = "", maxticks = 100, tickincr = 1):
|
||||
self.title = title
|
||||
self.msg = msg
|
||||
self.maxticks = maxticks
|
||||
self.tickincr = tickincr
|
||||
self.dialog = None
|
||||
WinThread.__init__(self)
|
||||
self.createdEvent = threading.Event()
|
||||
|
||||
def InitInstance(self):
|
||||
self.dialog = CThreadedStatusProcessDialog( self.title, self.msg, self.maxticks, self.tickincr)
|
||||
self.dialog.CreateWindow()
|
||||
try:
|
||||
self.dialog.SetForegroundWindow()
|
||||
except win32ui.error:
|
||||
pass
|
||||
self.createdEvent.set()
|
||||
return WinThread.InitInstance(self)
|
||||
|
||||
def ExitInstance(self):
|
||||
return 0
|
||||
|
||||
|
||||
def StatusProgressDialog(title, msg = "", maxticks = 100, parent = None):
|
||||
d = CStatusProgressDialog (title, msg, maxticks)
|
||||
d.CreateWindow (parent)
|
||||
return d
|
||||
|
||||
def ThreadedStatusProgressDialog(title, msg = "", maxticks = 100):
|
||||
t = ProgressThread(title, msg, maxticks)
|
||||
t.CreateThread()
|
||||
# Need to run a basic "PumpWaitingMessages" loop just incase we are
|
||||
# running inside Pythonwin.
|
||||
# Basic timeout incase things go terribly wrong. Ideally we should use
|
||||
# win32event.MsgWaitForMultipleObjects(), but we use a threading module
|
||||
# event - so use a dumb strategy
|
||||
end_time = time.time() + 10
|
||||
while time.time() < end_time:
|
||||
if t.createdEvent.isSet():
|
||||
break
|
||||
win32ui.PumpWaitingMessages()
|
||||
time.sleep(0.1)
|
||||
return t.dialog
|
||||
|
||||
def demo():
|
||||
d = StatusProgressDialog("A Demo", "Doing something...")
|
||||
import win32api
|
||||
for i in range(100):
|
||||
if i == 50:
|
||||
d.SetText("Getting there...")
|
||||
if i==90:
|
||||
d.SetText("Nearly done...")
|
||||
win32api.Sleep(20)
|
||||
d.Tick()
|
||||
d.Close()
|
||||
|
||||
def thread_demo():
|
||||
d = ThreadedStatusProgressDialog("A threaded demo", "Doing something")
|
||||
import win32api
|
||||
for i in range(100):
|
||||
if i == 50:
|
||||
d.SetText("Getting there...")
|
||||
if i==90:
|
||||
d.SetText("Nearly done...")
|
||||
win32api.Sleep(20)
|
||||
d.Tick()
|
||||
d.Close()
|
||||
|
||||
if __name__=='__main__':
|
||||
thread_demo()
|
||||
#demo()
|
|
@ -1,541 +0,0 @@
|
|||
# DockingBar.py
|
||||
|
||||
# Ported directly (comments and all) from the samples at www.codeguru.com
|
||||
|
||||
# WARNING: Use at your own risk, as this interface is highly likely to change.
|
||||
# Currently we support only one child per DockingBar. Later we need to add
|
||||
# support for multiple children.
|
||||
|
||||
import win32api, win32con, win32ui
|
||||
from pywin.mfc import afxres, window
|
||||
import struct
|
||||
|
||||
clrBtnHilight = win32api.GetSysColor(win32con.COLOR_BTNHILIGHT)
|
||||
clrBtnShadow = win32api.GetSysColor(win32con.COLOR_BTNSHADOW)
|
||||
|
||||
def CenterPoint(rect):
|
||||
width = rect[2]-rect[0]
|
||||
height = rect[3]-rect[1]
|
||||
return rect[0] + width//2, rect[1] + height//2
|
||||
|
||||
def OffsetRect(rect, point):
|
||||
(x, y) = point
|
||||
return rect[0]+x, rect[1]+y, rect[2]+x, rect[3]+y
|
||||
|
||||
def DeflateRect(rect, point):
|
||||
(x, y) = point
|
||||
return rect[0]+x, rect[1]+y, rect[2]-x, rect[3]-y
|
||||
|
||||
def PtInRect(rect, pt):
|
||||
return rect[0] <= pt[0] < rect[2] and rect[1] <= pt[1] < rect[3]
|
||||
|
||||
class DockingBar(window.Wnd):
|
||||
def __init__(self, obj=None):
|
||||
if obj is None:
|
||||
obj = win32ui.CreateControlBar()
|
||||
window.Wnd.__init__(self, obj)
|
||||
self.dialog = None
|
||||
self.nDockBarID = 0
|
||||
self.sizeMin = 32, 32
|
||||
self.sizeHorz = 200, 200
|
||||
self.sizeVert = 200, 200
|
||||
self.sizeFloat = 200, 200
|
||||
self.bTracking = 0
|
||||
self.bInRecalcNC = 0
|
||||
self.cxEdge = 6
|
||||
self.cxBorder = 3
|
||||
self.cxGripper = 20
|
||||
self.brushBkgd = win32ui.CreateBrush()
|
||||
self.brushBkgd.CreateSolidBrush(win32api.GetSysColor(win32con.COLOR_BTNFACE))
|
||||
|
||||
# Support for diagonal resizing
|
||||
self.cyBorder = 3
|
||||
self.cCaptionSize = win32api.GetSystemMetrics(win32con.SM_CYSMCAPTION)
|
||||
self.cMinWidth = win32api.GetSystemMetrics(win32con.SM_CXMIN)
|
||||
self.cMinHeight = win32api.GetSystemMetrics(win32con.SM_CYMIN)
|
||||
self.rectUndock = (0,0,0,0)
|
||||
|
||||
def OnUpdateCmdUI(self, target, bDisableIfNoHndler):
|
||||
return self.UpdateDialogControls(target, bDisableIfNoHndler)
|
||||
|
||||
def CreateWindow(self, parent, childCreator, title, id, style=win32con.WS_CHILD | win32con.WS_VISIBLE | afxres.CBRS_LEFT, childCreatorArgs=()):
|
||||
assert not ((style & afxres.CBRS_SIZE_FIXED) and (style & afxres.CBRS_SIZE_DYNAMIC)), "Invalid style"
|
||||
self.rectClose = self.rectBorder = self.rectGripper = self.rectTracker = 0,0,0,0
|
||||
|
||||
# save the style
|
||||
self._obj_.dwStyle = style & afxres.CBRS_ALL
|
||||
|
||||
cursor = win32api.LoadCursor(0, win32con.IDC_ARROW)
|
||||
wndClass = win32ui.RegisterWndClass(win32con.CS_DBLCLKS, cursor, self.brushBkgd.GetSafeHandle(), 0)
|
||||
|
||||
self._obj_.CreateWindow(wndClass, title, style, (0,0,0,0), parent, id)
|
||||
|
||||
# Create the child dialog
|
||||
self.dialog = childCreator(*(self,) + childCreatorArgs)
|
||||
|
||||
# use the dialog dimensions as default base dimensions
|
||||
assert self.dialog.IsWindow(), "The childCreator function %s did not create a window!" % childCreator
|
||||
rect = self.dialog.GetWindowRect()
|
||||
self.sizeHorz = self.sizeVert = self.sizeFloat = rect[2]-rect[0], rect[3]-rect[1]
|
||||
|
||||
self.sizeHorz = self.sizeHorz[0], self.sizeHorz[1] + self.cxEdge + self.cxBorder
|
||||
self.sizeVert = self.sizeVert[0] + self.cxEdge + self.cxBorder, self.sizeVert[1]
|
||||
self.HookMessages()
|
||||
|
||||
def CalcFixedLayout(self, bStretch, bHorz):
|
||||
rectTop = self.dockSite.GetControlBar(afxres.AFX_IDW_DOCKBAR_TOP).GetWindowRect()
|
||||
rectLeft = self.dockSite.GetControlBar(afxres.AFX_IDW_DOCKBAR_LEFT).GetWindowRect()
|
||||
if bStretch:
|
||||
nHorzDockBarWidth = 32767
|
||||
nVertDockBarHeight = 32767
|
||||
else:
|
||||
nHorzDockBarWidth = rectTop[2]-rectTop[0] + 4
|
||||
nVertDockBarHeight = rectLeft[3]-rectLeft[1] + 4
|
||||
|
||||
if self.IsFloating():
|
||||
return self.sizeFloat
|
||||
if bHorz:
|
||||
return nHorzDockBarWidth, self.sizeHorz[1]
|
||||
return self.sizeVert[0], nVertDockBarHeight
|
||||
|
||||
def CalcDynamicLayout(self, length, mode):
|
||||
# Support for diagonal sizing.
|
||||
if self.IsFloating():
|
||||
self.GetParent().GetParent().ModifyStyle(win32ui.MFS_4THICKFRAME, 0)
|
||||
if mode & (win32ui.LM_HORZDOCK | win32ui.LM_VERTDOCK):
|
||||
flags = win32con.SWP_NOSIZE | win32con.SWP_NOMOVE | win32con.SWP_NOZORDER |\
|
||||
win32con.SWP_NOACTIVATE | win32con.SWP_FRAMECHANGED
|
||||
self.SetWindowPos(0, (0, 0, 0, 0,), flags)
|
||||
self.dockSite.RecalcLayout()
|
||||
return self._obj_.CalcDynamicLayout(length, mode)
|
||||
|
||||
if mode & win32ui.LM_MRUWIDTH:
|
||||
return self.sizeFloat
|
||||
if mode & win32ui.LM_COMMIT:
|
||||
self.sizeFloat = length, self.sizeFloat[1]
|
||||
return self.sizeFloat
|
||||
# More diagonal sizing.
|
||||
if self.IsFloating():
|
||||
dc = self.dockContext
|
||||
pt = win32api.GetCursorPos()
|
||||
windowRect = self.GetParent().GetParent().GetWindowRect()
|
||||
|
||||
hittest = dc.nHitTest
|
||||
if hittest==win32con.HTTOPLEFT:
|
||||
cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder
|
||||
cy = max(windowRect[3] - self.cCaptionSize - pt[1],self.cMinHeight) - 1
|
||||
self.sizeFloat = cx, cy
|
||||
|
||||
top = min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) - self.cyBorder
|
||||
left = min(pt[0], windowRect[2] - self.cMinWidth) - 1
|
||||
dc.rectFrameDragHorz = left, top, dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
||||
return self.sizeFloat
|
||||
if hittest==win32con.HTTOPRIGHT:
|
||||
cx = max(pt[0] - windowRect[0], self.cMinWidth)
|
||||
cy = max(windowRect[3] - self.cCaptionSize - pt[1], self.cMinHeight) - 1
|
||||
self.sizeFloat = cx, cy
|
||||
|
||||
top = min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) - self.cyBorder
|
||||
dc.rectFrameDragHorz = dc.rectFrameDragHorz[0], top, dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
||||
return self.sizeFloat
|
||||
|
||||
if hittest==win32con.HTBOTTOMLEFT:
|
||||
cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder
|
||||
cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight)
|
||||
self.sizeFloat = cx, cy
|
||||
|
||||
left = min(pt[0], windowRect[2] -self.cMinWidth) - 1
|
||||
dc.rectFrameDragHorz = left, dc.rectFrameDragHorz[1], dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
||||
return self.sizeFloat
|
||||
|
||||
if hittest==win32con.HTBOTTOMRIGHT:
|
||||
cx = max(pt[0] - windowRect[0], self.cMinWidth)
|
||||
cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight)
|
||||
self.sizeFloat = cx, cy
|
||||
return self.sizeFloat
|
||||
|
||||
if mode & win32ui.LM_LENGTHY:
|
||||
self.sizeFloat = self.sizeFloat[0], max(self.sizeMin[1], length)
|
||||
return self.sizeFloat
|
||||
else:
|
||||
return max(self.sizeMin[0], length), self.sizeFloat[1]
|
||||
|
||||
def OnWindowPosChanged(self, msg):
|
||||
if self.GetSafeHwnd()==0 or self.dialog is None:
|
||||
return 0
|
||||
lparam = msg[3]
|
||||
""" LPARAM used with WM_WINDOWPOSCHANGED:
|
||||
typedef struct {
|
||||
HWND hwnd;
|
||||
HWND hwndInsertAfter;
|
||||
int x;
|
||||
int y;
|
||||
int cx;
|
||||
int cy;
|
||||
UINT flags;} WINDOWPOS;
|
||||
"""
|
||||
format = "PPiiiii"
|
||||
bytes = win32ui.GetBytes( lparam, struct.calcsize(format) )
|
||||
hwnd, hwndAfter, x, y, cx, cy, flags = struct.unpack(format, bytes)
|
||||
|
||||
if self.bInRecalcNC:
|
||||
rc = self.GetClientRect()
|
||||
self.dialog.MoveWindow(rc)
|
||||
return 0
|
||||
# Find on which side are we docked
|
||||
nDockBarID = self.GetParent().GetDlgCtrlID()
|
||||
# Return if dropped at same location
|
||||
# no docking side change and no size change
|
||||
if (nDockBarID == self.nDockBarID) and \
|
||||
(flags & win32con.SWP_NOSIZE) and \
|
||||
((self._obj_.dwStyle & afxres.CBRS_BORDER_ANY) != afxres.CBRS_BORDER_ANY):
|
||||
return
|
||||
self.nDockBarID = nDockBarID
|
||||
|
||||
# Force recalc the non-client area
|
||||
self.bInRecalcNC = 1
|
||||
try:
|
||||
swpflags = win32con.SWP_NOSIZE | win32con.SWP_NOMOVE | win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED
|
||||
self.SetWindowPos(0, (0,0,0,0), swpflags)
|
||||
finally:
|
||||
self.bInRecalcNC = 0
|
||||
return 0
|
||||
|
||||
# This is a virtual and not a message hook.
|
||||
def OnSetCursor(self, window, nHitTest, wMouseMsg):
|
||||
if nHitTest != win32con.HTSIZE or self.bTracking:
|
||||
return self._obj_.OnSetCursor(window, nHitTest, wMouseMsg)
|
||||
|
||||
if self.IsHorz():
|
||||
win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZENS))
|
||||
else:
|
||||
win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZEWE))
|
||||
return 1
|
||||
|
||||
# Mouse Handling
|
||||
def OnLButtonUp(self, msg):
|
||||
if not self.bTracking:
|
||||
return 1 # pass it on.
|
||||
self.StopTracking(1)
|
||||
return 0 # Dont pass on
|
||||
|
||||
def OnLButtonDown(self, msg):
|
||||
# UINT nFlags, CPoint point)
|
||||
# only start dragging if clicked in "void" space
|
||||
if self.dockBar is not None:
|
||||
# start the drag
|
||||
pt = msg[5]
|
||||
pt = self.ClientToScreen(pt)
|
||||
self.dockContext.StartDrag(pt)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def OnNcLButtonDown(self, msg):
|
||||
if self.bTracking: return 0
|
||||
nHitTest = wparam = msg[2]
|
||||
pt = msg[5]
|
||||
|
||||
if nHitTest==win32con.HTSYSMENU and not self.IsFloating():
|
||||
self.GetDockingFrame().ShowControlBar(self, 0, 0)
|
||||
elif nHitTest == win32con.HTMINBUTTON and not self.IsFloating():
|
||||
self.dockContext.ToggleDocking()
|
||||
elif nHitTest == win32con.HTCAPTION and not self.IsFloating() and self.dockBar is not None:
|
||||
self.dockContext.StartDrag(pt)
|
||||
elif nHitTest == win32con.HTSIZE and not self.IsFloating():
|
||||
self.StartTracking()
|
||||
else:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def OnLButtonDblClk(self, msg):
|
||||
# only toggle docking if clicked in "void" space
|
||||
if self.dockBar is not None:
|
||||
# toggle docking
|
||||
self.dockContext.ToggleDocking()
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def OnNcLButtonDblClk(self, msg):
|
||||
nHitTest = wparam = msg[2]
|
||||
# UINT nHitTest, CPoint point)
|
||||
if self.dockBar is not None and nHitTest == win32con.HTCAPTION:
|
||||
# toggle docking
|
||||
self.dockContext.ToggleDocking()
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def OnMouseMove(self, msg):
|
||||
flags = wparam = msg[2]
|
||||
lparam = msg[3]
|
||||
if self.IsFloating() or not self.bTracking:
|
||||
return 1
|
||||
|
||||
# Convert unsigned 16 bit to signed 32 bit.
|
||||
x=win32api.LOWORD(lparam)
|
||||
if x & 32768: x = x | -65536
|
||||
y = win32api.HIWORD(lparam)
|
||||
if y & 32768: y = y | -65536
|
||||
pt = x, y
|
||||
cpt = CenterPoint(self.rectTracker)
|
||||
pt = self.ClientToWnd(pt)
|
||||
if self.IsHorz():
|
||||
if cpt[1] != pt[1]:
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
self.rectTracker = OffsetRect(self.rectTracker, (0, pt[1] - cpt[1]))
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
else:
|
||||
if cpt[0] != pt[0]:
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
self.rectTracker = OffsetRect(self.rectTracker, (pt[0]-cpt[0], 0))
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
|
||||
return 0 # Dont pass it on.
|
||||
|
||||
# def OnBarStyleChange(self, old, new):
|
||||
|
||||
def OnNcCalcSize(self, bCalcValid, size_info):
|
||||
(rc0, rc1, rc2, pos) = size_info
|
||||
self.rectBorder = self.GetWindowRect()
|
||||
self.rectBorder = OffsetRect( self.rectBorder, (-self.rectBorder[0], -self.rectBorder[1]) )
|
||||
|
||||
dwBorderStyle = self._obj_.dwStyle | afxres.CBRS_BORDER_ANY
|
||||
|
||||
if self.nDockBarID==afxres.AFX_IDW_DOCKBAR_TOP:
|
||||
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_BOTTOM;
|
||||
rc0.left = rc0.left + self.cxGripper
|
||||
rc0.bottom = rc0.bottom-self.cxEdge
|
||||
rc0.top = rc0.top + self.cxBorder
|
||||
rc0.right = rc0.right - self.cxBorder
|
||||
self.rectBorder = self.rectBorder[0], self.rectBorder[3]-self.cxEdge, self.rectBorder[2], self.rectBorder[3]
|
||||
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
||||
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_TOP
|
||||
rc0.left = rc0.left + self.cxGripper
|
||||
rc0.top = rc0.top + self.cxEdge
|
||||
rc0.bottom = rc0.bottom - self.cxBorder
|
||||
rc0.right = rc0.right - self.cxBorder
|
||||
self.rectBorder = self.rectBorder[0], self.rectBorder[1], self.rectBorder[2], self.rectBorder[1]+self.cxEdge
|
||||
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_LEFT:
|
||||
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_RIGHT
|
||||
rc0.right = rc0.right - self.cxEdge
|
||||
rc0.left = rc0.left + self.cxBorder
|
||||
rc0.bottom = rc0.bottom - self.cxBorder
|
||||
rc0.top = rc0.top + self.cxGripper
|
||||
self.rectBorder = self.rectBorder[2] - self.cxEdge, self.rectBorder[1], self.rectBorder[2], self.rectBorder[3]
|
||||
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_RIGHT:
|
||||
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_LEFT
|
||||
rc0.left = rc0.left + self.cxEdge
|
||||
rc0.right = rc0.right - self.cxBorder
|
||||
rc0.bottom = rc0.bottom - self.cxBorder
|
||||
rc0.top = rc0.top + self.cxGripper
|
||||
self.rectBorder = self.rectBorder[0], self.rectBorder[1], self.rectBorder[0]+self.cxEdge, self.rectBorder[3]
|
||||
else:
|
||||
self.rectBorder = 0,0,0,0
|
||||
|
||||
self.SetBarStyle(dwBorderStyle)
|
||||
return 0
|
||||
|
||||
def OnNcPaint(self, msg):
|
||||
self.EraseNonClient()
|
||||
dc = self.GetWindowDC()
|
||||
ctl = win32api.GetSysColor(win32con.COLOR_BTNHIGHLIGHT)
|
||||
cbr = win32api.GetSysColor(win32con.COLOR_BTNSHADOW)
|
||||
dc.Draw3dRect(self.rectBorder, ctl, cbr)
|
||||
|
||||
self.DrawGripper(dc)
|
||||
|
||||
rect = self.GetClientRect()
|
||||
self.InvalidateRect( rect, 1)
|
||||
return 0
|
||||
|
||||
def OnNcHitTest(self, pt): # A virtual, not a hooked message.
|
||||
if self.IsFloating():
|
||||
return 1
|
||||
|
||||
ptOrig = pt
|
||||
rect = self.GetWindowRect()
|
||||
pt = pt[0] - rect[0], pt[1] - rect[1]
|
||||
|
||||
if PtInRect(self.rectClose, pt):
|
||||
return win32con.HTSYSMENU
|
||||
elif PtInRect(self.rectUndock, pt):
|
||||
return win32con.HTMINBUTTON
|
||||
elif PtInRect(self.rectGripper, pt):
|
||||
return win32con.HTCAPTION
|
||||
elif PtInRect(self.rectBorder, pt):
|
||||
return win32con.HTSIZE
|
||||
else:
|
||||
return self._obj_.OnNcHitTest(ptOrig)
|
||||
|
||||
def StartTracking(self):
|
||||
self.SetCapture()
|
||||
|
||||
# make sure no updates are pending
|
||||
self.RedrawWindow(None, None, win32con.RDW_ALLCHILDREN | win32con.RDW_UPDATENOW)
|
||||
self.dockSite.LockWindowUpdate()
|
||||
|
||||
self.ptOld = CenterPoint(self.rectBorder)
|
||||
self.bTracking = 1
|
||||
|
||||
self.rectTracker = self.rectBorder;
|
||||
if not self.IsHorz():
|
||||
l, t, r, b = self.rectTracker
|
||||
b = b - 4
|
||||
self.rectTracker = l, t, r, b
|
||||
|
||||
self.OnInvertTracker(self.rectTracker);
|
||||
|
||||
def OnCaptureChanged(self, msg):
|
||||
hwnd = lparam = msg[3]
|
||||
if self.bTracking and hwnd != self.GetSafeHwnd():
|
||||
self.StopTracking(0) # cancel tracking
|
||||
return 1
|
||||
|
||||
def StopTracking(self, bAccept):
|
||||
self.OnInvertTracker(self.rectTracker)
|
||||
self.dockSite.UnlockWindowUpdate()
|
||||
self.bTracking = 0
|
||||
self.ReleaseCapture()
|
||||
if not bAccept: return
|
||||
|
||||
rcc = self.dockSite.GetWindowRect()
|
||||
if self.IsHorz():
|
||||
newsize = self.sizeHorz[1]
|
||||
maxsize = newsize + (rcc[3]-rcc[1])
|
||||
minsize = self.sizeMin[1]
|
||||
else:
|
||||
newsize = self.sizeVert[0]
|
||||
maxsize = newsize + (rcc[2]-rcc[0])
|
||||
minsize = self.sizeMin[0]
|
||||
|
||||
pt = CenterPoint(self.rectTracker)
|
||||
if self.nDockBarID== afxres.AFX_IDW_DOCKBAR_TOP:
|
||||
newsize = newsize + (pt[1] - self.ptOld[1])
|
||||
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
||||
newsize = newsize + (- pt[1] + self.ptOld[1])
|
||||
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_LEFT:
|
||||
newsize = newsize + (pt[0] - self.ptOld[0])
|
||||
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_RIGHT:
|
||||
newsize = newsize + (- pt[0] + self.ptOld[0])
|
||||
newsize = max(minsize, min(maxsize, newsize))
|
||||
if self.IsHorz():
|
||||
self.sizeHorz = self.sizeHorz[0], newsize
|
||||
else:
|
||||
self.sizeVert = newsize, self.sizeVert[1]
|
||||
self.dockSite.RecalcLayout()
|
||||
return 0
|
||||
|
||||
def OnInvertTracker(self, rect):
|
||||
assert rect[2]-rect[0]>0 and rect[3]-rect[1]>0, "rect is empty"
|
||||
assert self.bTracking
|
||||
rcc = self.GetWindowRect()
|
||||
rcf = self.dockSite.GetWindowRect()
|
||||
|
||||
rect = OffsetRect(rect, (rcc[0] - rcf[0], rcc[1] - rcf[1]))
|
||||
rect = DeflateRect(rect, (1, 1));
|
||||
|
||||
flags = win32con.DCX_WINDOW|win32con.DCX_CACHE|win32con.DCX_LOCKWINDOWUPDATE
|
||||
dc = self.dockSite.GetDCEx(None, flags)
|
||||
try:
|
||||
brush = win32ui.GetHalftoneBrush()
|
||||
oldBrush = dc.SelectObject(brush)
|
||||
|
||||
dc.PatBlt((rect[0], rect[1]), (rect[2]-rect[0], rect[3]-rect[1]), win32con.PATINVERT)
|
||||
dc.SelectObject(oldBrush)
|
||||
finally:
|
||||
self.dockSite.ReleaseDC(dc)
|
||||
|
||||
def IsHorz(self):
|
||||
return self.nDockBarID == afxres.AFX_IDW_DOCKBAR_TOP or \
|
||||
self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM
|
||||
|
||||
def ClientToWnd(self, pt):
|
||||
x, y=pt
|
||||
if self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
||||
y = y + self.cxEdge
|
||||
elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT:
|
||||
x = x + self.cxEdge
|
||||
return x,y
|
||||
|
||||
def DrawGripper(self, dc):
|
||||
# no gripper if floating
|
||||
if self._obj_.dwStyle & afxres.CBRS_FLOATING:
|
||||
return
|
||||
|
||||
# -==HACK==-
|
||||
# in order to calculate the client area properly after docking,
|
||||
# the client area must be recalculated twice (I have no idea why)
|
||||
self.dockSite.RecalcLayout()
|
||||
# -==END HACK==-
|
||||
|
||||
gripper = self.GetWindowRect()
|
||||
gripper = self.ScreenToClient( gripper )
|
||||
gripper = OffsetRect( gripper, (-gripper[0], -gripper[1]) )
|
||||
gl, gt, gr, gb = gripper
|
||||
|
||||
if self._obj_.dwStyle & afxres.CBRS_ORIENT_HORZ:
|
||||
# gripper at left
|
||||
self.rectGripper = gl, gt + 40, gl+20, gb
|
||||
# draw close box
|
||||
self.rectClose = gl+7, gt + 10, gl+19, gt+22
|
||||
dc.DrawFrameControl(self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE)
|
||||
# draw docking toggle box
|
||||
self.rectUndock = OffsetRect(self.rectClose, (0,13))
|
||||
dc.DrawFrameControl(self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX);
|
||||
|
||||
gt = gt + 38
|
||||
gb = gb - 10
|
||||
gl = gl + 10
|
||||
gr = gl + 3
|
||||
gripper = gl, gt, gr, gb
|
||||
dc.Draw3dRect( gripper, clrBtnHilight, clrBtnShadow )
|
||||
dc.Draw3dRect( OffsetRect(gripper, (4,0)), clrBtnHilight, clrBtnShadow )
|
||||
else:
|
||||
# gripper at top
|
||||
self.rectGripper = gl, gt, gr-40, gt+20
|
||||
# draw close box
|
||||
self.rectClose = gr-21, gt+7, gr-10, gt+18
|
||||
dc.DrawFrameControl(self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE)
|
||||
# draw docking toggle box
|
||||
self.rectUndock = OffsetRect( self.rectClose, (-13,0) )
|
||||
dc.DrawFrameControl(self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX)
|
||||
gr = gr - 38;
|
||||
gl = gl + 10
|
||||
gt = gt + 10
|
||||
gb = gt + 3
|
||||
|
||||
gripper = gl, gt, gr, gb
|
||||
dc.Draw3dRect( gripper, clrBtnHilight, clrBtnShadow )
|
||||
dc.Draw3dRect( OffsetRect(gripper, (0,4) ), clrBtnHilight, clrBtnShadow )
|
||||
|
||||
def HookMessages(self):
|
||||
self.HookMessage(self.OnLButtonUp, win32con.WM_LBUTTONUP)
|
||||
self.HookMessage(self.OnLButtonDown, win32con.WM_LBUTTONDOWN)
|
||||
self.HookMessage(self.OnLButtonDblClk, win32con.WM_LBUTTONDBLCLK)
|
||||
self.HookMessage(self.OnNcLButtonDown, win32con.WM_NCLBUTTONDOWN)
|
||||
self.HookMessage(self.OnNcLButtonDblClk, win32con.WM_NCLBUTTONDBLCLK)
|
||||
self.HookMessage(self.OnMouseMove, win32con.WM_MOUSEMOVE)
|
||||
self.HookMessage(self.OnNcPaint, win32con.WM_NCPAINT)
|
||||
self.HookMessage(self.OnCaptureChanged, win32con.WM_CAPTURECHANGED)
|
||||
self.HookMessage(self.OnWindowPosChanged, win32con.WM_WINDOWPOSCHANGED)
|
||||
# self.HookMessage(self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
def EditCreator(parent):
|
||||
d = win32ui.CreateEdit()
|
||||
es = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.ES_MULTILINE | win32con.ES_WANTRETURN
|
||||
d.CreateWindow( es, (0,0,150,150), parent, 1000)
|
||||
return d
|
||||
|
||||
def test():
|
||||
import pywin.mfc.dialog
|
||||
global bar
|
||||
bar = DockingBar()
|
||||
creator = EditCreator
|
||||
bar.CreateWindow(win32ui.GetMainFrame(), creator, "Coolbar Demo",0xfffff)
|
||||
# win32ui.GetMainFrame().ShowControlBar(bar, 1, 0)
|
||||
bar.SetBarStyle( bar.GetBarStyle()|afxres.CBRS_TOOLTIPS|afxres.CBRS_FLYBY|afxres.CBRS_SIZE_DYNAMIC)
|
||||
bar.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
||||
win32ui.GetMainFrame().DockControlBar(bar, afxres.AFX_IDW_DOCKBAR_BOTTOM)
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
|
@ -1,408 +0,0 @@
|
|||
# App.py
|
||||
# Application stuff.
|
||||
# The application is responsible for managing the main frame window.
|
||||
#
|
||||
# We also grab the FileOpen command, to invoke our Python editor
|
||||
" The PythonWin application code. Manages most aspects of MDI, etc "
|
||||
import win32con
|
||||
import win32api
|
||||
import win32ui
|
||||
import sys
|
||||
import string
|
||||
import os
|
||||
from pywin.mfc import window, dialog, afxres
|
||||
from pywin.mfc.thread import WinApp
|
||||
import traceback
|
||||
import regutil
|
||||
|
||||
from . import scriptutils
|
||||
|
||||
## NOTE: App and AppBuild should NOT be used - instead, you should contruct your
|
||||
## APP class manually whenever you like (just ensure you leave these 2 params None!)
|
||||
## Whoever wants the generic "Application" should get it via win32iu.GetApp()
|
||||
|
||||
# These are "legacy"
|
||||
AppBuilder = None
|
||||
App = None # default - if used, must end up a CApp derived class.
|
||||
|
||||
# Helpers that should one day be removed!
|
||||
def AddIdleHandler(handler):
|
||||
print("app.AddIdleHandler is deprecated - please use win32ui.GetApp().AddIdleHandler() instead.")
|
||||
return win32ui.GetApp().AddIdleHandler(handler)
|
||||
def DeleteIdleHandler(handler):
|
||||
print("app.DeleteIdleHandler is deprecated - please use win32ui.GetApp().DeleteIdleHandler() instead.")
|
||||
return win32ui.GetApp().DeleteIdleHandler(handler)
|
||||
|
||||
# Helper for writing a Window position by name, and later loading it.
|
||||
def SaveWindowSize(section,rect,state=""):
|
||||
""" Writes a rectangle to an INI file
|
||||
Args: section = section name in the applications INI file
|
||||
rect = a rectangle in a (cy, cx, y, x) tuple
|
||||
(same format as CREATESTRUCT position tuples)."""
|
||||
left, top, right, bottom = rect
|
||||
if state: state = state + " "
|
||||
win32ui.WriteProfileVal(section,state+"left",left)
|
||||
win32ui.WriteProfileVal(section,state+"top",top)
|
||||
win32ui.WriteProfileVal(section,state+"right",right)
|
||||
win32ui.WriteProfileVal(section,state+"bottom",bottom)
|
||||
|
||||
def LoadWindowSize(section, state=""):
|
||||
""" Loads a section from an INI file, and returns a rect in a tuple (see SaveWindowSize)"""
|
||||
if state: state = state + " "
|
||||
left = win32ui.GetProfileVal(section,state+"left",0)
|
||||
top = win32ui.GetProfileVal(section,state+"top",0)
|
||||
right = win32ui.GetProfileVal(section,state+"right",0)
|
||||
bottom = win32ui.GetProfileVal(section,state+"bottom",0)
|
||||
return (left, top, right, bottom)
|
||||
|
||||
def RectToCreateStructRect(rect):
|
||||
return (rect[3]-rect[1], rect[2]-rect[0], rect[1], rect[0] )
|
||||
|
||||
|
||||
# Define FrameWindow and Application objects
|
||||
#
|
||||
# The Main Frame of the application.
|
||||
class MainFrame(window.MDIFrameWnd):
|
||||
sectionPos = "Main Window"
|
||||
statusBarIndicators = ( afxres.ID_SEPARATOR, #// status line indicator
|
||||
afxres.ID_INDICATOR_CAPS,
|
||||
afxres.ID_INDICATOR_NUM,
|
||||
afxres.ID_INDICATOR_SCRL,
|
||||
win32ui.ID_INDICATOR_LINENUM,
|
||||
win32ui.ID_INDICATOR_COLNUM )
|
||||
|
||||
def OnCreate(self, cs):
|
||||
self._CreateStatusBar()
|
||||
return 0
|
||||
|
||||
def _CreateStatusBar(self):
|
||||
self.statusBar = win32ui.CreateStatusBar(self)
|
||||
self.statusBar.SetIndicators(self.statusBarIndicators)
|
||||
self.HookCommandUpdate(self.OnUpdatePosIndicator, win32ui.ID_INDICATOR_LINENUM)
|
||||
self.HookCommandUpdate(self.OnUpdatePosIndicator, win32ui.ID_INDICATOR_COLNUM)
|
||||
|
||||
def OnUpdatePosIndicator(self, cmdui):
|
||||
editControl = scriptutils.GetActiveEditControl()
|
||||
value = " " * 5
|
||||
if editControl is not None:
|
||||
try:
|
||||
startChar, endChar = editControl.GetSel()
|
||||
lineNo = editControl.LineFromChar(startChar)
|
||||
colNo = endChar - editControl.LineIndex(lineNo)
|
||||
|
||||
if cmdui.m_nID==win32ui.ID_INDICATOR_LINENUM:
|
||||
value = "%0*d" % (5, lineNo + 1)
|
||||
else:
|
||||
value = "%0*d" % (3, colNo + 1)
|
||||
except win32ui.error:
|
||||
pass
|
||||
cmdui.SetText(value)
|
||||
cmdui.Enable()
|
||||
|
||||
def PreCreateWindow(self, cc):
|
||||
cc = self._obj_.PreCreateWindow(cc)
|
||||
pos = LoadWindowSize(self.sectionPos)
|
||||
self.startRect = pos
|
||||
if pos[2] - pos[0]:
|
||||
rect = RectToCreateStructRect(pos)
|
||||
cc = cc[0], cc[1], cc[2], cc[3], rect, cc[5], cc[6], cc[7], cc[8]
|
||||
return cc
|
||||
|
||||
def OnDestroy(self, msg):
|
||||
# use GetWindowPlacement(), as it works even when min'd or max'd
|
||||
rectNow = self.GetWindowPlacement()[4]
|
||||
if rectNow != self.startRect:
|
||||
SaveWindowSize(self.sectionPos, rectNow)
|
||||
return 0
|
||||
|
||||
class CApp(WinApp):
|
||||
" A class for the application "
|
||||
def __init__(self):
|
||||
self.oldCallbackCaller = None
|
||||
WinApp.__init__(self, win32ui.GetApp() )
|
||||
self.idleHandlers = []
|
||||
|
||||
def InitInstance(self):
|
||||
" Called to crank up the app "
|
||||
HookInput()
|
||||
numMRU = win32ui.GetProfileVal("Settings","Recent File List Size", 10)
|
||||
win32ui.LoadStdProfileSettings(numMRU)
|
||||
# self._obj_.InitMDIInstance()
|
||||
if win32api.GetVersionEx()[0]<4:
|
||||
win32ui.SetDialogBkColor()
|
||||
win32ui.Enable3dControls()
|
||||
|
||||
# install a "callback caller" - a manager for the callbacks
|
||||
# self.oldCallbackCaller = win32ui.InstallCallbackCaller(self.CallbackManager)
|
||||
self.LoadMainFrame()
|
||||
self.SetApplicationPaths()
|
||||
|
||||
def ExitInstance(self):
|
||||
" Called as the app dies - too late to prevent it here! "
|
||||
win32ui.OutputDebug("Application shutdown\n")
|
||||
# Restore the callback manager, if any.
|
||||
try:
|
||||
win32ui.InstallCallbackCaller(self.oldCallbackCaller)
|
||||
except AttributeError:
|
||||
pass
|
||||
if self.oldCallbackCaller:
|
||||
del self.oldCallbackCaller
|
||||
self.frame=None # clean Python references to the now destroyed window object.
|
||||
self.idleHandlers = []
|
||||
# Attempt cleanup if not already done!
|
||||
if self._obj_: self._obj_.AttachObject(None)
|
||||
self._obj_ = None
|
||||
global App
|
||||
global AppBuilder
|
||||
App = None
|
||||
AppBuilder = None
|
||||
return 0
|
||||
|
||||
def HaveIdleHandler(self, handler):
|
||||
return handler in self.idleHandlers
|
||||
def AddIdleHandler(self, handler):
|
||||
self.idleHandlers.append(handler)
|
||||
def DeleteIdleHandler(self, handler):
|
||||
self.idleHandlers.remove(handler)
|
||||
def OnIdle(self, count):
|
||||
try:
|
||||
ret = 0
|
||||
handlers = self.idleHandlers[:] # copy list, as may be modified during loop
|
||||
for handler in handlers:
|
||||
try:
|
||||
thisRet = handler(handler, count)
|
||||
except:
|
||||
print("Idle handler %s failed" % (repr(handler)))
|
||||
traceback.print_exc()
|
||||
print("Idle handler removed from list")
|
||||
try:
|
||||
self.DeleteIdleHandler(handler)
|
||||
except ValueError: # Item not in list.
|
||||
pass
|
||||
thisRet = 0
|
||||
ret = ret or thisRet
|
||||
return ret
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
def CreateMainFrame(self):
|
||||
return MainFrame()
|
||||
|
||||
def LoadMainFrame(self):
|
||||
" Create the main applications frame "
|
||||
self.frame = self.CreateMainFrame()
|
||||
self.SetMainFrame(self.frame)
|
||||
self.frame.LoadFrame(win32ui.IDR_MAINFRAME, win32con.WS_OVERLAPPEDWINDOW)
|
||||
self.frame.DragAcceptFiles() # we can accept these.
|
||||
self.frame.ShowWindow(win32ui.GetInitialStateRequest())
|
||||
self.frame.UpdateWindow()
|
||||
self.HookCommands()
|
||||
|
||||
def OnHelp(self,id, code):
|
||||
try:
|
||||
if id==win32ui.ID_HELP_GUI_REF:
|
||||
helpFile = regutil.GetRegisteredHelpFile("Pythonwin Reference")
|
||||
helpCmd = win32con.HELP_CONTENTS
|
||||
else:
|
||||
helpFile = regutil.GetRegisteredHelpFile("Main Python Documentation")
|
||||
helpCmd = win32con.HELP_FINDER
|
||||
if helpFile is None:
|
||||
win32ui.MessageBox("The help file is not registered!")
|
||||
else:
|
||||
from . import help
|
||||
help.OpenHelpFile(helpFile, helpCmd)
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
win32ui.MessageBox("Internal error in help file processing\r\n%s: %s" % (t,v))
|
||||
tb = None # Prevent a cycle
|
||||
|
||||
def DoLoadModules(self, modules):
|
||||
# XXX - this should go, but the debugger uses it :-(
|
||||
# dont do much checking!
|
||||
for module in modules:
|
||||
__import__(module)
|
||||
|
||||
def HookCommands(self):
|
||||
self.frame.HookMessage(self.OnDropFiles,win32con.WM_DROPFILES)
|
||||
self.HookCommand(self.HandleOnFileOpen,win32ui.ID_FILE_OPEN)
|
||||
self.HookCommand(self.HandleOnFileNew,win32ui.ID_FILE_NEW)
|
||||
self.HookCommand(self.OnFileMRU,win32ui.ID_FILE_MRU_FILE1)
|
||||
self.HookCommand(self.OnHelpAbout,win32ui.ID_APP_ABOUT)
|
||||
self.HookCommand(self.OnHelp, win32ui.ID_HELP_PYTHON)
|
||||
self.HookCommand(self.OnHelp, win32ui.ID_HELP_GUI_REF)
|
||||
# Hook for the right-click menu.
|
||||
self.frame.GetWindow(win32con.GW_CHILD).HookMessage(self.OnRClick,win32con.WM_RBUTTONDOWN)
|
||||
|
||||
def SetApplicationPaths(self):
|
||||
# Load the users/application paths
|
||||
new_path = []
|
||||
apppath=win32ui.GetProfileVal('Python','Application Path','').split(';')
|
||||
for path in apppath:
|
||||
if len(path)>0:
|
||||
new_path.append(win32ui.FullPath(path))
|
||||
for extra_num in range(1,11):
|
||||
apppath=win32ui.GetProfileVal('Python','Application Path %d'%extra_num,'').split(';')
|
||||
if len(apppath) == 0:
|
||||
break
|
||||
for path in apppath:
|
||||
if len(path)>0:
|
||||
new_path.append(win32ui.FullPath(path))
|
||||
sys.path = new_path + sys.path
|
||||
|
||||
def OnRClick(self,params):
|
||||
" Handle right click message "
|
||||
# put up the entire FILE menu!
|
||||
menu = win32ui.LoadMenu(win32ui.IDR_TEXTTYPE).GetSubMenu(0)
|
||||
menu.TrackPopupMenu(params[5]) # track at mouse position.
|
||||
return 0
|
||||
|
||||
def OnDropFiles(self,msg):
|
||||
" Handle a file being dropped from file manager "
|
||||
hDropInfo = msg[2]
|
||||
self.frame.SetActiveWindow() # active us
|
||||
nFiles = win32api.DragQueryFile(hDropInfo)
|
||||
try:
|
||||
for iFile in range(0,nFiles):
|
||||
fileName = win32api.DragQueryFile(hDropInfo, iFile)
|
||||
win32ui.GetApp().OpenDocumentFile( fileName )
|
||||
finally:
|
||||
win32api.DragFinish(hDropInfo);
|
||||
|
||||
return 0
|
||||
|
||||
# No longer used by Pythonwin, as the C++ code has this same basic functionality
|
||||
# but handles errors slightly better.
|
||||
# It all still works, tho, so if you need similar functionality, you can use it.
|
||||
# Therefore I havent deleted this code completely!
|
||||
# def CallbackManager( self, ob, args = () ):
|
||||
# """Manage win32 callbacks. Trap exceptions, report on them, then return 'All OK'
|
||||
# to the frame-work. """
|
||||
# import traceback
|
||||
# try:
|
||||
# ret = apply(ob, args)
|
||||
# return ret
|
||||
# except:
|
||||
# # take copies of the exception values, else other (handled) exceptions may get
|
||||
# # copied over by the other fns called.
|
||||
# win32ui.SetStatusText('An exception occured in a windows command handler.')
|
||||
# t, v, tb = sys.exc_info()
|
||||
# traceback.print_exception(t, v, tb.tb_next)
|
||||
# try:
|
||||
# sys.stdout.flush()
|
||||
# except (NameError, AttributeError):
|
||||
# pass
|
||||
|
||||
# Command handlers.
|
||||
def OnFileMRU( self, id, code ):
|
||||
" Called when a File 1-n message is recieved "
|
||||
fileName = win32ui.GetRecentFileList()[id - win32ui.ID_FILE_MRU_FILE1]
|
||||
win32ui.GetApp().OpenDocumentFile(fileName)
|
||||
|
||||
def HandleOnFileOpen( self, id, code ):
|
||||
" Called when FileOpen message is received "
|
||||
win32ui.GetApp().OnFileOpen()
|
||||
|
||||
def HandleOnFileNew( self, id, code ):
|
||||
" Called when FileNew message is received "
|
||||
win32ui.GetApp().OnFileNew()
|
||||
|
||||
def OnHelpAbout( self, id, code ):
|
||||
" Called when HelpAbout message is received. Displays the About dialog. "
|
||||
win32ui.InitRichEdit()
|
||||
dlg=AboutBox()
|
||||
dlg.DoModal()
|
||||
|
||||
def _GetRegistryValue(key, val, default = None):
|
||||
# val is registry value - None for default val.
|
||||
try:
|
||||
hkey = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, key)
|
||||
return win32api.RegQueryValueEx(hkey, val)[0]
|
||||
except win32api.error:
|
||||
try:
|
||||
hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, key)
|
||||
return win32api.RegQueryValueEx(hkey, val)[0]
|
||||
except win32api.error:
|
||||
return default
|
||||
|
||||
scintilla = "Scintilla is Copyright 1998-2008 Neil Hodgson (http://www.scintilla.org)"
|
||||
idle = "This program uses IDLE extensions by Guido van Rossum, Tim Peters and others."
|
||||
contributors = "Thanks to the following people for making significant contributions: Roger Upole, Sidnei da Silva, Sam Rushing, Curt Hagenlocher, Dave Brennan, Roger Burnham, Gordon McMillan, Neil Hodgson, Laramie Leavitt. (let me know if I have forgotten you!)"
|
||||
# The About Box
|
||||
class AboutBox(dialog.Dialog):
|
||||
def __init__(self, idd=win32ui.IDD_ABOUTBOX):
|
||||
dialog.Dialog.__init__(self, idd)
|
||||
def OnInitDialog(self):
|
||||
text = "Pythonwin - Python IDE and GUI Framework for Windows.\n\n%s\n\nPython is %s\n\n%s\n\n%s\n\n%s" % (win32ui.copyright, sys.copyright, scintilla, idle, contributors)
|
||||
self.SetDlgItemText(win32ui.IDC_EDIT1, text)
|
||||
# Get the build number - written by installers.
|
||||
# For distutils build, read pywin32.version.txt
|
||||
import distutils.sysconfig
|
||||
site_packages = distutils.sysconfig.get_python_lib(plat_specific=1)
|
||||
try:
|
||||
build_no = open(os.path.join(site_packages, "pywin32.version.txt")).read().strip()
|
||||
ver = "pywin32 build %s" % build_no
|
||||
except EnvironmentError:
|
||||
ver = None
|
||||
if ver is None:
|
||||
# See if we are Part of Active Python
|
||||
ver = _GetRegistryValue("SOFTWARE\\ActiveState\\ActivePython", "CurrentVersion")
|
||||
if ver is not None:
|
||||
ver = "ActivePython build %s" % (ver,)
|
||||
if ver is None:
|
||||
ver = ""
|
||||
self.SetDlgItemText(win32ui.IDC_ABOUT_VERSION, ver)
|
||||
self.HookCommand(self.OnButHomePage, win32ui.IDC_BUTTON1)
|
||||
|
||||
def OnButHomePage(self, id, code):
|
||||
if code == win32con.BN_CLICKED:
|
||||
win32api.ShellExecute(0, "open", "https://github.com/mhammond/pywin32", None, "", 1)
|
||||
|
||||
def Win32RawInput(prompt=None):
|
||||
"Provide raw_input() for gui apps"
|
||||
# flush stderr/out first.
|
||||
try:
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
except:
|
||||
pass
|
||||
if prompt is None: prompt = ""
|
||||
ret=dialog.GetSimpleInput(prompt)
|
||||
if ret==None:
|
||||
raise KeyboardInterrupt("operation cancelled")
|
||||
return ret
|
||||
|
||||
def Win32Input(prompt=None):
|
||||
"Provide input() for gui apps"
|
||||
return eval(input(prompt))
|
||||
|
||||
def HookInput():
|
||||
try:
|
||||
raw_input
|
||||
# must be py2x...
|
||||
sys.modules['__builtin__'].raw_input=Win32RawInput
|
||||
sys.modules['__builtin__'].input=Win32Input
|
||||
except NameError:
|
||||
# must be py3k
|
||||
import code
|
||||
sys.modules['builtins'].input=Win32RawInput
|
||||
|
||||
def HaveGoodGUI():
|
||||
"""Returns true if we currently have a good gui available.
|
||||
"""
|
||||
return "pywin.framework.startup" in sys.modules
|
||||
|
||||
def CreateDefaultGUI( appClass = None):
|
||||
"""Creates a default GUI environment
|
||||
"""
|
||||
if appClass is None:
|
||||
from . import intpyapp # Bring in the default app - could be param'd later.
|
||||
appClass = intpyapp.InteractivePythonApp
|
||||
# Create and init the app.
|
||||
appClass().InitInstance()
|
||||
|
||||
def CheckCreateDefaultGUI():
|
||||
"""Checks and creates if necessary a default GUI environment.
|
||||
"""
|
||||
rc = HaveGoodGUI()
|
||||
if not rc:
|
||||
CreateDefaultGUI()
|
||||
return rc
|
|
@ -1,143 +0,0 @@
|
|||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import string
|
||||
import os
|
||||
from . import app
|
||||
import sys
|
||||
|
||||
from pywin.mfc import docview, window
|
||||
|
||||
bStretch = 1
|
||||
|
||||
class BitmapDocument(docview.Document):
|
||||
"A bitmap document. Holds the bitmap data itself."
|
||||
def __init__(self, template):
|
||||
docview.Document.__init__(self, template)
|
||||
self.bitmap=None
|
||||
def OnNewDocument(self):
|
||||
# I can not create new bitmaps.
|
||||
win32ui.MessageBox("Bitmaps can not be created.")
|
||||
def OnOpenDocument(self, filename):
|
||||
self.bitmap=win32ui.CreateBitmap()
|
||||
# init data members
|
||||
f = open(filename, 'rb')
|
||||
try:
|
||||
try:
|
||||
self.bitmap.LoadBitmapFile(f)
|
||||
except IOError:
|
||||
win32ui.MessageBox("Could not load the bitmap from %s" % filename)
|
||||
return 0
|
||||
finally:
|
||||
f.close()
|
||||
self.size = self.bitmap.GetSize()
|
||||
return 1
|
||||
def DeleteContents(self):
|
||||
self.bitmap=None
|
||||
|
||||
class BitmapView(docview.ScrollView):
|
||||
"A view of a bitmap. Obtains data from document."
|
||||
def __init__(self, doc):
|
||||
docview.ScrollView.__init__(self, doc)
|
||||
self.width = self.height = 0
|
||||
# set up message handlers
|
||||
self.HookMessage (self.OnSize, win32con.WM_SIZE)
|
||||
|
||||
def OnInitialUpdate(self):
|
||||
doc = self.GetDocument()
|
||||
if doc.bitmap:
|
||||
bitmapSize = doc.bitmap.GetSize()
|
||||
self.SetScrollSizes(win32con.MM_TEXT, bitmapSize)
|
||||
|
||||
def OnSize (self, params):
|
||||
lParam = params[3]
|
||||
self.width = win32api.LOWORD(lParam)
|
||||
self.height = win32api.HIWORD(lParam)
|
||||
|
||||
def OnDraw (self, dc):
|
||||
# set sizes used for "non stretch" mode.
|
||||
doc = self.GetDocument()
|
||||
if doc.bitmap is None: return
|
||||
bitmapSize = doc.bitmap.GetSize()
|
||||
if bStretch:
|
||||
# stretch BMP.
|
||||
viewRect = (0,0,self.width, self.height)
|
||||
bitmapRect = (0,0,bitmapSize[0], bitmapSize[1])
|
||||
doc.bitmap.Paint(dc, viewRect, bitmapRect)
|
||||
else:
|
||||
# non stretch.
|
||||
doc.bitmap.Paint(dc)
|
||||
|
||||
class BitmapFrame(window.MDIChildWnd):
|
||||
def OnCreateClient( self, createparams, context ):
|
||||
borderX = win32api.GetSystemMetrics(win32con.SM_CXFRAME)
|
||||
borderY = win32api.GetSystemMetrics(win32con.SM_CYFRAME)
|
||||
titleY = win32api.GetSystemMetrics(win32con.SM_CYCAPTION) # includes border
|
||||
# try and maintain default window pos, else adjust if cant fit
|
||||
# get the main client window dimensions.
|
||||
mdiClient = win32ui.GetMainFrame().GetWindow(win32con.GW_CHILD)
|
||||
clientWindowRect=mdiClient.ScreenToClient(mdiClient.GetWindowRect())
|
||||
clientWindowSize=(clientWindowRect[2]-clientWindowRect[0],clientWindowRect[3]-clientWindowRect[1])
|
||||
left, top, right, bottom=mdiClient.ScreenToClient(self.GetWindowRect())
|
||||
# width, height=context.doc.size[0], context.doc.size[1]
|
||||
# width = width+borderX*2
|
||||
# height= height+titleY+borderY*2-1
|
||||
# if (left+width)>clientWindowSize[0]:
|
||||
# left = clientWindowSize[0] - width
|
||||
# if left<0:
|
||||
# left = 0
|
||||
# width = clientWindowSize[0]
|
||||
# if (top+height)>clientWindowSize[1]:
|
||||
# top = clientWindowSize[1] - height
|
||||
# if top<0:
|
||||
# top = 0
|
||||
# height = clientWindowSize[1]
|
||||
# self.frame.MoveWindow((left, top, left+width, top+height),0)
|
||||
window.MDIChildWnd.OnCreateClient(self, createparams, context)
|
||||
return 1
|
||||
|
||||
|
||||
class BitmapTemplate(docview.DocTemplate):
|
||||
def __init__(self):
|
||||
docview.DocTemplate.__init__(self, win32ui.IDR_PYTHONTYPE, BitmapDocument, BitmapFrame, BitmapView)
|
||||
def MatchDocType(self, fileName, fileType):
|
||||
doc = self.FindOpenDocument(fileName)
|
||||
if doc: return doc
|
||||
ext = os.path.splitext(fileName)[1].lower()
|
||||
if ext =='.bmp': # removed due to PIL! or ext=='.ppm':
|
||||
return win32ui.CDocTemplate_Confidence_yesAttemptNative
|
||||
return win32ui.CDocTemplate_Confidence_maybeAttemptForeign
|
||||
# return win32ui.CDocTemplate_Confidence_noAttempt
|
||||
|
||||
# For debugging purposes, when this module may be reloaded many times.
|
||||
try:
|
||||
win32ui.GetApp().RemoveDocTemplate(bitmapTemplate)
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
bitmapTemplate = BitmapTemplate()
|
||||
bitmapTemplate.SetDocStrings('\nBitmap\nBitmap\nBitmap (*.bmp)\n.bmp\nPythonBitmapFileType\nPython Bitmap File')
|
||||
win32ui.GetApp().AddDocTemplate(bitmapTemplate)
|
||||
|
||||
# This works, but just didnt make it through the code reorg.
|
||||
#class PPMBitmap(Bitmap):
|
||||
# def LoadBitmapFile(self, file ):
|
||||
# magic=file.readline()
|
||||
# if magic <> "P6\n":
|
||||
# raise TypeError, "The file is not a PPM format file"
|
||||
# rowcollist=string.split(file.readline())
|
||||
# cols=string.atoi(rowcollist[0])
|
||||
# rows=string.atoi(rowcollist[1])
|
||||
# file.readline() # whats this one?
|
||||
# self.bitmap.LoadPPMFile(file,(cols,rows))
|
||||
|
||||
|
||||
def t():
|
||||
bitmapTemplate.OpenDocumentFile('d:\\winnt\\arcade.bmp')
|
||||
#OpenBMPFile( 'd:\\winnt\\arcade.bmp')
|
||||
|
||||
def demo():
|
||||
import glob
|
||||
winDir=win32api.GetWindowsDirectory()
|
||||
for fileName in glob.glob1(winDir, '*.bmp')[:2]:
|
||||
bitmapTemplate.OpenDocumentFile(os.path.join(winDir, fileName))
|
|
@ -1,49 +0,0 @@
|
|||
# cmdline - command line utilities.
|
||||
import sys
|
||||
import win32ui
|
||||
import string
|
||||
|
||||
def ParseArgs( str ):
|
||||
import string
|
||||
ret=[]
|
||||
pos = 0
|
||||
length=len(str)
|
||||
while pos<length:
|
||||
try:
|
||||
while str[pos] in string.whitespace: pos = pos+1
|
||||
except IndexError:
|
||||
break
|
||||
if pos>=length:
|
||||
break
|
||||
if str[pos]=='"':
|
||||
pos=pos+1
|
||||
try:
|
||||
endPos = str.index('"', pos)-1
|
||||
nextPos = endPos+2
|
||||
except ValueError:
|
||||
endPos=length
|
||||
nextPos=endPos+1
|
||||
else:
|
||||
endPos = pos
|
||||
while endPos<length and not str[endPos] in string.whitespace: endPos = endPos+1
|
||||
nextPos=endPos+1
|
||||
ret.append(str[pos:endPos+1].strip())
|
||||
pos = nextPos
|
||||
return ret
|
||||
|
||||
def FixArgFileName(fileName):
|
||||
"""Convert a filename on the commandline to something useful.
|
||||
Given an automatic filename on the commandline, turn it a python module name,
|
||||
with the path added to sys.path. """
|
||||
import os
|
||||
path, fname = os.path.split(fileName)
|
||||
if len(path)==0:
|
||||
path = os.curdir
|
||||
path=os.path.abspath(path)
|
||||
# must check that the command line arg's path is in sys.path
|
||||
for syspath in sys.path:
|
||||
if os.path.abspath(syspath)==path:
|
||||
break
|
||||
else:
|
||||
sys.path.append(path)
|
||||
return os.path.splitext(fname)[0]
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue