[Zope3-checkins] SVN: Zope3/branches/Zope-3.1/ Merged revisions
38059, 38136 from the trunk:
Dmitry Vasiliev
dima at hlabs.spb.ru
Fri Sep 2 03:25:19 EDT 2005
Log message for revision 38234:
Merged revisions 38059, 38136 from the trunk:
Rev 38059:
Removed duplicate and unused interface
Rev 38136:
Fixed issue #445: gadflyDA not full implementation
Changed:
U Zope3/branches/Zope-3.1/doc/CHANGES.txt
U Zope3/branches/Zope-3.1/src/zope/app/rdb/__init__.py
U Zope3/branches/Zope-3.1/src/zope/app/rdb/interfaces.py
U Zope3/branches/Zope-3.1/src/zope/app/rdb/tests/test_gadflyadapter.py
U Zope3/branches/Zope-3.1/src/zope/app/rdb/tests/test_zopecursor.py
-=-
Modified: Zope3/branches/Zope-3.1/doc/CHANGES.txt
===================================================================
--- Zope3/branches/Zope-3.1/doc/CHANGES.txt 2005-09-02 00:40:39 UTC (rev 38233)
+++ Zope3/branches/Zope-3.1/doc/CHANGES.txt 2005-09-02 07:25:19 UTC (rev 38234)
@@ -658,6 +658,8 @@
Bug Fixes
+ - Fixed issue #445: gadflyDA not full implementation
+
- Request factories were not uniformly pluggable. All are pluggable now
without having to write a new server.
Modified: Zope3/branches/Zope-3.1/src/zope/app/rdb/__init__.py
===================================================================
--- Zope3/branches/Zope-3.1/src/zope/app/rdb/__init__.py 2005-09-02 00:40:39 UTC (rev 38233)
+++ Zope3/branches/Zope-3.1/src/zope/app/rdb/__init__.py 2005-09-02 07:25:19 UTC (rev 38234)
@@ -290,21 +290,28 @@
return self.cursor.execute(operation)
return self.cursor.execute(operation, parameters)
+ def executemany(self, operation, parameters):
+ """Executes an operation, registering the underlying
+ connection with the transaction system. """
+ operation, parameters = self._prepareOperation(operation, parameters)
+ method = getattr(self.cursor, "executemany", self.cursor.execute)
+ self.connection.registerForTxn()
+ return method(operation, parameters)
+
def _prepareOperation(self, operation, parameters):
encoding = self.connection.getTypeInfo().getEncoding()
if isinstance(operation, unicode):
operation = operation.encode(encoding)
+ parameters = self._prepareParameters(parameters, encoding)
+ return operation, parameters
+ def _prepareParameters(self, parameters, encoding):
if isinstance(parameters, list):
for i, v in enumerate(parameters):
if isinstance(v, unicode):
parameters[i] = v.encode(encoding)
- elif isinstance(v, tuple):
- values = list(v)
- for j, v in enumerate(values):
- if isinstance(v, unicode):
- values[j] = v.encode(encoding)
- parameters[i] = tuple(values)
+ else:
+ parameters[i] = self._prepareParameters(v, encoding)
elif isinstance(parameters, tuple):
parameters = list(parameters)
for i, v in enumerate(parameters):
@@ -315,7 +322,7 @@
for k, v in parameters.items():
if isinstance(v, unicode):
parameters[k] = v.encode(encoding)
- return operation, parameters
+ return parameters
def __getattr__(self, key):
return getattr(self.cursor, key)
Modified: Zope3/branches/Zope-3.1/src/zope/app/rdb/interfaces.py
===================================================================
--- Zope3/branches/Zope-3.1/src/zope/app/rdb/interfaces.py 2005-09-02 00:40:39 UTC (rev 38233)
+++ Zope3/branches/Zope-3.1/src/zope/app/rdb/interfaces.py 2005-09-02 07:25:19 UTC (rev 38234)
@@ -20,6 +20,7 @@
from zope.schema import TextLine
from zope.app.i18n import ZopeMessageIDFactory as _
+
class IDBITypeInfoProvider(Interface):
"""This object can get the Type Info for a particular DBI
implementation."""
@@ -27,7 +28,6 @@
def getTypeInfo():
"""Return an IDBITypeInfo object."""
-
class IDBITypeInfo(Interface):
"""Database adapter specific information"""
@@ -74,120 +74,6 @@
def getConverter(type):
"""Return a converter function for field type matching key"""
-
-arraysize = 1 # default constant, symbolic
-
-class ICursor(Interface):
- """DB API ICursor interface"""
-
- description = Attribute("""This read-only attribute is a sequence of
- 7-item sequences. Each of these sequences contains information
- describing one result column: (name, type_code, display_size,
- internal_size, precision, scale, null_ok). This attribute will be None
- for operations that do not return rows or if the cursor has not had an
- operation invoked via the executeZZZ() method yet.
-
- The type_code can be interpreted by comparing it to the Type Objects
- specified in the section below. """)
-
- arraysize = Attribute("""This read/write attribute specifies the number of
- rows to fetch at a time with fetchmany(). It defaults to 1 meaning to
- fetch a single row at a time.
-
- Implementations must observe this value with respect to the
- fetchmany() method, but are free to interact with the database a
- single row at a time. It may also be used in the implementation of
- executemany().
- """)
-
- def close():
- """Close the cursor now (rather than whenever __del__ is called). The
- cursor will be unusable from this point forward; an Error (or
- subclass) exception will be raised if any operation is attempted with
- the cursor.
- """
-
- def execute(operation, parameters=None):
- """Prepare and execute a database operation (query or
- command). Parameters may be provided as sequence or mapping and will
- be bound to variables in the operation. Variables are specified in a
- database-specific notation (see the module's paramstyle attribute for
- details). [5]
-
- A reference to the operation will be retained by the cursor. If the
- same operation object is passed in again, then the cursor can optimize
- its behavior. This is most effective for algorithms where the same
- operation is used, but different parameters are bound to it (many
- times).
-
- For maximum efficiency when reusing an operation, it is best to use
- the setinputsizes() method to specify the parameter types and sizes
- ahead of time. It is legal for a parameter to not match the predefined
- information; the implementation should compensate, possibly with a
- loss of efficiency.
-
- The parameters may also be specified as list of tuples to e.g. insert
- multiple rows in a single operation, but this kind of usage is
- depreciated: executemany() should be used instead.
-
- Return values are not defined.
- """
-
-
- def executemany(operation, seq_of_parameters):
- """Prepare a database operation (query or command) and then execute it
- against all parameter sequences or mappings found in the sequence
- seq_of_parameters.
-
- Modules are free to implement this method using multiple calls to the
- execute() method or by using array operations to have the database
- process the sequence as a whole in one call.
-
- The same comments as for execute() also apply accordingly to this
- method.
-
- Return values are not defined.
- """
-
- def fetchone():
- """Fetch the next row of a query result set, returning a single
- sequence, or None when no more data is available.
-
- An Error (or subclass) exception is raised if the previous call to
- executeZZZ() did not produce any result set or no call was issued yet.
- """
-
- def fetchmany(size=arraysize):
- """Fetch the next set of rows of a query result, returning a sequence
- of sequences (e.g. a list of tuples). An empty sequence is returned
- when no more rows are available.
-
- The number of rows to fetch per call is specified by the parameter. If
- it is not given, the cursor's arraysize determines the number of rows
- to be fetched. The method should try to fetch as many rows as
- indicated by the size parameter. If this is not possible due to the
- specified number of rows not being available, fewer rows may be
- returned.
-
- An Error (or subclass) exception is raised if the previous call to
- executeZZZ() did not produce any result set or no call was issued yet.
-
- Note there are performance considerations involved with the size
- parameter. For optimal performance, it is usually best to use the
- arraysize attribute. If the size parameter is used, then it is best
- for it to retain the same value from one fetchmany() call to the next.
- """
-
- def fetchall():
- """Fetch all (remaining) rows of a query result, returning them as a
- sequence of sequences (e.g. a list of tuples). Note that the cursor's
- arraysize attribute can affect the performance of this operation.
-
- An Error (or subclass) exception is raised if the previous call to
- executeZZZ() did not produce any result set or no call was issued yet.
- """
-
-
class IResultSet(Interface):
"""Holds results, and allows iteration."""
@@ -207,6 +93,7 @@
def __str__(self):
return self.message
+arraysize = 1 # default constant, symbolic
class IDBICursor(Interface):
"""DB API ICursor interface"""
@@ -264,7 +151,6 @@
Return values are not defined.
"""
-
def executemany(operation, seq_of_parameters):
"""Prepare a database operation (query or command) and then execute it
against all parameter sequences or mappings found in the sequence
@@ -318,12 +204,11 @@
executeZZZ() did not produce any result set or no call was issued yet.
"""
-
class IDBIConnection(Interface):
"""A DB-API based Interface """
def cursor():
- """Return a new ICursor Object using the connection.
+ """Return a new IDBICursor Object using the connection.
If the database does not provide a direct cursor concept, the module
will have to emulate cursors using other means to the extent needed by
@@ -351,7 +236,6 @@
attempted with the connection. The same applies to all cursor objects
trying to use the connection. """
-
class ISQLCommand(Interface):
"""Static SQL commands."""
@@ -364,8 +248,6 @@
def __call__():
"""Execute an sql query and return a result object if appropriate"""
-
-
class IZopeDatabaseAdapter(IDBITypeInfo):
"""Interface for persistent object that returns
volatile IZopeConnections."""
@@ -413,7 +295,6 @@
"""Database adapters with management functions
"""
-
class IZopeConnection(IDBIConnection, IDBITypeInfoProvider):
# An implementation of this object will be exposed to the
@@ -431,20 +312,19 @@
manager.
"""
-
class IZopeCursor(IDBICursor):
- """An ICursor that integrates with Zope's transactions"""
+ """An IDBICursor that integrates with Zope's transactions"""
def execute(operation, parameters=None):
"""Executes an operation, registering the underlying connection with
the transaction system.
- See ICursor for more detailed execute information.
+ See IDBICursor for more detailed execute information.
"""
- def executemany(operation, seq_of_parameters=None):
+ def executemany(operation, seq_of_parameters):
"""Executes an operation, registering the underlying connection with
the transaction system.
- See ICursor for more detailed executemany information.
+ See IDBICursor for more detailed executemany information.
"""
Modified: Zope3/branches/Zope-3.1/src/zope/app/rdb/tests/test_gadflyadapter.py
===================================================================
--- Zope3/branches/Zope-3.1/src/zope/app/rdb/tests/test_gadflyadapter.py 2005-09-02 00:40:39 UTC (rev 38233)
+++ Zope3/branches/Zope-3.1/src/zope/app/rdb/tests/test_gadflyadapter.py 2005-09-02 07:25:19 UTC (rev 38234)
@@ -19,9 +19,13 @@
import tempfile
from unittest import TestCase, TestSuite, main, makeSuite
+from zope.interface.verify import verifyObject
+
from zope.app.rdb import DatabaseAdapterError
+from zope.app.rdb.interfaces import IZopeConnection, IZopeCursor
from zope.app.rdb.gadflyda import GadflyAdapter, setGadflyRoot
+
class GadflyTestBase(TestCase):
def setUp(self):
@@ -42,8 +46,7 @@
return self.tempdir
def _create(self, *args):
- obj = GadflyAdapter(*args)
- return obj
+ return GadflyAdapter(*args)
class TestGadflyAdapter(GadflyTestBase):
@@ -131,7 +134,14 @@
conn = a._connection_factory()
conn.rollback() # is it really a connection?
+ def test__interfaces(self):
+ a = self._create("dbi://demo")
+ connection = a()
+ verifyObject(IZopeConnection, connection)
+ cursor = connection.cursor()
+ verifyObject(IZopeCursor, cursor)
+
def test_suite():
return TestSuite((
makeSuite(TestGadflyAdapter),
Modified: Zope3/branches/Zope-3.1/src/zope/app/rdb/tests/test_zopecursor.py
===================================================================
--- Zope3/branches/Zope-3.1/src/zope/app/rdb/tests/test_zopecursor.py 2005-09-02 00:40:39 UTC (rev 38233)
+++ Zope3/branches/Zope-3.1/src/zope/app/rdb/tests/test_zopecursor.py 2005-09-02 07:25:19 UTC (rev 38234)
@@ -25,7 +25,11 @@
def cursor(self):
return MyCursorStub()
+class MyConnectionStub2(ConnectionStub):
+ def cursor(self):
+ return MyCursorStub2()
+
raw = [['mano', 2, 'buvo batai'],
['dingo', 1, 'nerandu'],
['as su', 1, 'batuku'],
@@ -44,6 +48,7 @@
description = ((None, 'string'), (None, 'int'), (None, 'foo'))
def execute(self, query, args=None):
+ self.method = "execute"
self.query = query
self.args = args
@@ -59,7 +64,14 @@
def fetchmany(self, size=2):
return self._raw[:size]
+class MyCursorStub2(MyCursorStub):
+ def executemany(self, query, args):
+ self.method = "executemany"
+ self.query = query
+ self.args = args
+
+
class MyTypeInfoStub(TypeInfoStub):
def getConverter(self, type):
@@ -125,6 +137,19 @@
'got %r,\n'
'expected %r' % (results, expected))
+ def test_cursor_executemany(self):
+ self.cursor.executemany("SELECT", [("A",), ("B",)])
+ self.assertEqual("execute", self.cursor.cursor.method)
+ self.assertEqual("SELECT", self.cursor.cursor.query)
+ self.assertEqual([("A",), ("B",)], self.cursor.cursor.args)
+
+ zc = ZopeConnection(MyConnectionStub2(), self.typeInfo)
+ self.cursor = ZopeCursor(zc.conn.cursor(), zc)
+ self.cursor.executemany("SELECT", [("A",), ("B",)])
+ self.assertEqual("executemany", self.cursor.cursor.method)
+ self.assertEqual("SELECT", self.cursor.cursor.query)
+ self.assertEqual([("A",), ("B",)], self.cursor.cursor.args)
+
def test_cursor_query_encoding(self):
self.cursor.execute(u'\u0422\u0435\u0441\u0442')
self.assertEqual('\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82',
@@ -151,6 +176,15 @@
[(u'\u0422\u0435\u0441\u0442',)])
self.assertEqual([('\xd2\xe5\xf1\xf2',)], self.cursor.cursor.args)
+ self.cursor.execute("SELECT * FROM table",
+ [[u'\u0422\u0435\u0441\u0442']])
+ self.assertEqual([['\xd2\xe5\xf1\xf2']], self.cursor.cursor.args)
+
+ self.cursor.execute("SELECT * FROM table",
+ [{"value": u'\u0422\u0435\u0441\u0442'}])
+ self.assertEqual([{"value": '\xd2\xe5\xf1\xf2'}],
+ self.cursor.cursor.args)
+
def test_cursor_dict_args_encoding(self):
self.typeInfo.setEncoding("windows-1251")
self.cursor.execute("SELECT * FROM table",
More information about the Zope3-Checkins
mailing list