install pywin32-220

This commit is contained in:
j 2016-04-14 21:54:42 +02:00
commit 93f7d415a0
581 changed files with 100203 additions and 0 deletions

View file

@ -0,0 +1,56 @@
"""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__

View file

@ -0,0 +1,276 @@
# 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

View file

@ -0,0 +1,70 @@
""" 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()

View file

@ -0,0 +1,19 @@
""" 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)

View file

@ -0,0 +1,38 @@
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()

View file

@ -0,0 +1,32 @@
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')))

View file

@ -0,0 +1,33 @@
"""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()))

View file

@ -0,0 +1,506 @@
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!

View file

@ -0,0 +1,92 @@
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).

View file

@ -0,0 +1,14 @@
"""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

View file

@ -0,0 +1,161 @@
# 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'

View file

@ -0,0 +1,899 @@
#!/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.'
)

View file

@ -0,0 +1,33 @@
"""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()))

View file

@ -0,0 +1,113 @@
#!/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')

View file

@ -0,0 +1,181 @@
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)

View file

@ -0,0 +1,46 @@
# 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'

View file

@ -0,0 +1,48 @@
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'