/usr/lib/python2.7/dist-packages/twext/enterprise/ienterprise.py is in calendarserver 5.2+dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | ##
# Copyright (c) 2010-2014 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
"""
Interfaces, mostly related to L{twext.enterprise.adbapi2}.
"""
__all__ = [
"IAsyncTransaction",
"ISQLExecutor",
"ICommandBlock",
"IQueuer",
"IDerivedParameter",
"AlreadyFinishedError",
"ConnectionError",
"POSTGRES_DIALECT",
"SQLITE_DIALECT",
"ORACLE_DIALECT",
"ORACLE_TABLE_NAME_MAX",
]
from zope.interface import Interface, Attribute
class AlreadyFinishedError(Exception):
"""
The transaction was already completed via an C{abort} or C{commit} and
cannot be aborted or committed again.
"""
class ConnectionError(Exception):
"""
An error occurred with the underlying database connection.
"""
POSTGRES_DIALECT = 'postgres-dialect'
ORACLE_DIALECT = 'oracle-dialect'
SQLITE_DIALECT = 'sqlite-dialect'
ORACLE_TABLE_NAME_MAX = 30
class ISQLExecutor(Interface):
"""
Base SQL-execution interface, for a group of commands or a transaction.
"""
paramstyle = Attribute(
"""
A copy of the 'paramstyle' attribute from a DB-API 2.0 module.
""")
dialect = Attribute(
"""
A copy of the 'dialect' attribute from the connection pool. One of the
C{*_DIALECT} constants in this module, such as C{POSTGRES_DIALECT}.
""")
def execSQL(sql, args=(), raiseOnZeroRowCount=None):
"""
Execute some SQL.
@param sql: an SQL string.
@type sql: C{str}
@param args: C{list} of arguments to interpolate into C{sql}.
@param raiseOnZeroRowCount: a 0-argument callable which returns an
exception to raise if the executed SQL does not affect any rows.
@return: L{Deferred} which fires C{list} of C{tuple}
@raise: C{raiseOnZeroRowCount} if it was specified and no rows were
affected.
"""
class IAsyncTransaction(ISQLExecutor):
"""
Asynchronous execution of SQL.
Note that there is no C{begin()} method; if an L{IAsyncTransaction} exists
at all, it is assumed to have been started.
"""
def commit():
"""
Commit changes caused by this transaction.
@return: L{Deferred} which fires with C{None} upon successful
completion of this transaction, or fails if this transaction could
not be committed. It fails with L{AlreadyFinishedError} if the
transaction has already been committed or rolled back.
"""
def preCommit(operation):
"""
Perform the given operation when this L{IAsyncTransaction}'s C{commit}
method is called, but before the underlying transaction commits. If
any exception is raised by this operation, underlying database commit
will be blocked and rollback run instead.
@param operation: a 0-argument callable that may return a L{Deferred}.
If it does, then the subsequent operations added by L{postCommit}
will not fire until that L{Deferred} fires.
"""
def postCommit(operation):
"""
Perform the given operation only after this L{IAsyncTransaction}
commits. These will be invoked before the L{Deferred} returned by
L{IAsyncTransaction.commit} fires.
@param operation: a 0-argument callable that may return a L{Deferred}.
If it does, then the subsequent operations added by L{postCommit}
will not fire until that L{Deferred} fires.
"""
def abort():
"""
Roll back changes caused by this transaction.
@return: L{Deferred} which fires with C{None} upon successful
rollback of this transaction.
"""
def postAbort(operation):
"""
Invoke a callback after abort.
@see: L{IAsyncTransaction.postCommit}
@param operation: 0-argument callable, potentially returning a
L{Deferred}.
"""
def commandBlock():
"""
Create an object which will cause the commands executed on it to be
grouped together.
This is useful when using database-specific features such as
sub-transactions where order of execution is importnat, but where
application code may need to perform I/O to determine what SQL,
exactly, it wants to execute. Consider this fairly contrived example
for an imaginary database::
def storeWebPage(url, block):
block.execSQL("BEGIN SUB TRANSACTION")
got = getPage(url)
def gotPage(data):
block.execSQL("INSERT INTO PAGES (TEXT) VALUES (?)",
[data])
block.execSQL("INSERT INTO INDEX (TOKENS) VALUES (?)",
[tokenize(data)])
lastStmt = block.execSQL("END SUB TRANSACTION")
block.end()
return lastStmt
return got.addCallback(gotPage)
gatherResults([storeWebPage(url, txn.commandBlock())
for url in urls]).addCallbacks(
lambda x: txn.commit(), lambda f: txn.abort()
)
This fires off all the C{getPage} requests in parallel, and prepares
all the necessary SQL immediately as the results arrive, but executes
those statements in order. In the above example, this makes sure to
store the page and its tokens together, another use for this might be
to store a computed aggregate (such as a sum) at a particular point in
a transaction, without sacrificing parallelism.
@rtype: L{ICommandBlock}
"""
class ICommandBlock(ISQLExecutor):
"""
This is a block of SQL commands that are grouped together.
@see: L{IAsyncTransaction.commandBlock}
"""
def end():
"""
End this command block, allowing other commands queued on the
underlying transaction to end.
@note: This is I{not} the same as either L{IAsyncTransaction.commit} or
L{IAsyncTransaction.abort}, since it does not denote success or
failure; merely that the command block has completed and other
statements may now be executed. Since sub-transactions are a
database-specific feature, they must be implemented at a
higher-level than this facility provides (although this facility
may be useful in their implementation). Also note that, unlike
either of those methods, this does I{not} return a Deferred: if you
want to know when the block has completed, simply add a callback to
the last L{ICommandBlock.execSQL} call executed on this
L{ICommandBlock}. (This may be changed in a future version for the
sake of convenience, however.)
"""
class IDerivedParameter(Interface):
"""
A parameter which needs to be derived from the underlying DB-API cursor;
implicitly, meaning that this must also interact with the actual thread
manipulating said cursor. If a provider of this interface is passed in the
C{args} argument to L{IAsyncTransaction.execSQL}, it will have its
C{prequery} and C{postquery} methods invoked on it before and after
executing the SQL query in question, respectively.
@note: L{IDerivedParameter} providers must also always be I{pickleable},
because in some cases the actual database cursor objects will be on the
other end of a network connection. For an explanation of why this
might be, see L{twext.enterprise.adbapi2.ConnectionPoolConnection}.
"""
def preQuery(cursor):
"""
Before running a query, invoke this method with the cursor that the
query will be run on.
(This can be used, for example, to allocate a special database-specific
variable based on the cursor, like an out parameter.)
@param cursor: the DB-API cursor.
@return: the concrete value which should be passed to the DB-API layer.
"""
def postQuery(cursor):
"""
After running a query, invoke this method in the DB-API thread.
(This can be used, for example, to manipulate any state created in the
preQuery method.)
@param cursor: the DB-API cursor.
@return: C{None}
"""
class IQueuer(Interface):
"""
An L{IQueuer} can enqueue work for later execution.
"""
def enqueueWork(self, transaction, workItemType, **kw):
"""
Perform some work, eventually.
@param transaction: an L{IAsyncTransaction} within which to I{commit}
to doing the work. Note that this work will likely be done later
(but depending on various factors, may actually be done within this
transaction as well).
@param workItemType: the type of work item to create.
@type workItemType: L{type}, specifically, a subtype of L{WorkItem
<twext.enterprise.queue.WorkItem>}
@param kw: The keyword parameters are relayed to C{workItemType.create}
to create an appropriately initialized item.
@return: a work proposal that allows tracking of the various phases of
completion of the work item.
@rtype: L{twext.enterprise.queue.WorkItem}
"""
def callWithNewProposals(self, callback):
"""
Tells the IQueuer to call a callback method whenever a new WorkProposal
is created.
@param callback: a callable which accepts a single parameter, a
L{WorkProposal}
"""
def transferProposalCallbacks(self, newQueuer):
"""
Transfer the registered callbacks to the new queuer.
"""
|