CM Frontend Reference¶
This module is an EXOS CM frontend that implements PEP-249, the Python Database API Specification v2.0.
See also
Connection¶
-
exos.api.cmfrontend.
connect
(username)[source]¶ Create a connection to the database. This will return an instance of the
Connection
class.
-
class
exos.api.cmfrontend.
Connection
(username, print_callback=None)[source]¶ Represents a logical connection to CM as a frontend for PEP-249 compliance. Connections must be created using
connect()
.CM does not have the concept of a connection, but this class will manage initialization of the underlying library. It also serves as a factory for
Cursor
instances.-
close
()[source]¶ Close this connection now. This is a no-op as CM does not have the concept of connections.
-
Cursor¶
-
class
exos.api.cmfrontend.
Cursor
(connection, vr_name=None)[source]¶ Object to manage the execution of a request. Cursors are created from the
Connection.cursor()
method. Cursors are stateful and operate on a singleRequest
at a time. The state is reset with every call toexecute()
.-
retries
¶ Number of times to retry a request if a module is unavailable. A module may be unavailable while it is restarting. By default, set to 0 so retries are not attempted.
-
vr_name
¶ Name of the current VR context. This will be passed to the backend module along with the request, encouraging it to run the request in the context of the given VR. Only a handful of modules are VR context aware, so usually this can be left alone. Defaults to
None
, indicating no VR context.
-
messages
¶ List of messages received from CM while executing a request. Per PEP-249, this list is cleared on
execute()
. The same list instance is used for the life of the cursor.
-
connection
¶ Per PEP-249, the
Connection
to which this cursor is associated. Read-only.
-
description
¶ Per PEP-249, sequence of sequences describing the table over which this cursor is executing. Read-only and set after an
execute()
.Only the two mandatory items, name and type_code, are provided. The name is that specified in
Request.add_field()
. The type_code is alwaysSTRING
.
-
rowcount
¶ Per PEP-249, number of rows affected by the last sequence. Always -1, indicating not supported.
-
rownumber
¶ Per PEP-249, read-only attribute providing the current 0-based index of the cursor in the result set. The next fetch operation will fetch the row indexed by rownumber. In other words, after an execute(), it will be 0. After the first
fetchone()
, it will be 1. And so on. Before an execute(), it will be None.
-
arraysize
¶ Per PEP-249, number of rows we’ll fetch at a time from the CM. Always 1.
-
execute
(req, param_values=None)[source]¶ Prepare and execute the given req with the optional param_values.
req must be a Request instance created with
request()
. Additionally, req must be valid, which means all tables have indexes, all parameters have values, etc., so that complete CM requests can be built.param_values must be a dictionary mapping each parameter name to a value.
-
fetchrows
()[source]¶ Fetch all remaining rows of an operation, returning them as a sequence of
Row
objects. Similar toiterrow()
, except that this method blocks untils all rows have been loaded into memory.
-
iterrow
()[source]¶ Generator that produces all remaining rows of an operation, returning them as
Row
objects. Similar tofetchrows()
, except that rows are returned as they are received. The next row is fetched asynchronously.
-
fetchone
()[source]¶ Per PEP-249, fetch the next row of an operation, returning a single sequence, or None when no more data is available. The field order in sequence matches the field order in the executed Request if specified, else will be unordered.
-
fetchall
()[source]¶ Per PEP-249, fetch all remaining rows of an operation, returning them as a sequence of sequences (e.g. a list of tuples). Similar to
__iter__()
, except that this method blocks until all rows have been loaded into memory.
-
next
()[source]¶ Implement an iterator by calling fetchone() and raising StopIteration as appropriate.
-
__iter__
()[source]¶ Per PEP-249, return an iterator that produces all remaining rows of an operation, returning each as a single sequence. Similar to
fetchall()
, except that rows are returned as they are received. The next row is fetched asynchronously.
-
Request¶
-
exos.api.cmfrontend.
request
(op=CM_OP_GET, outer_join=False)[source]¶ Create a new
Request
instance, which can be used as an operation when callingCursor.execute()
.op is
CM_OP_GET
orCM_OP_SET
. The default is a GET.If outer_join is True, we’ll peform a “left outer join”. In a “left outer join”, the row is still returned, but the missing data is replaced with
None
. If outer_join is False, the default, we’ll perform an “inner join”. In an “inner join”, the resulting row is only returned if data could be retrieved from all joined tables.
-
class
exos.api.cmfrontend.
Table
(module_name, table_name)[source]¶ Uniquely identifies a table within CM. Tables are scoped to a module, so this is a tuple of (module_name, table_name). Table instances are immutable.
-
__init__
(module_name, table_name)[source]¶ Create a new Table instance. module_name is the backend that owns the table. table_name identifies the table. Both are strings.
-
module_name
¶ Name of the table’s module.
-
table_name
¶ Name of the table.
-
-
class
exos.api.cmfrontend.
Column
(table, *args)[source]¶ Uniquely identify a column within CM. Columns are scoped to a
Table
, so this is a tuple of (table, column_name), which can also be thought of as (module_name, table_name, column_name). Column instances are immutable.-
__init__
(table, column_name)[source]¶ Create a Column instance given a table and column_name. table can be an instance of
Table
or a tuple of (module_name, table_name), in which case a Table instance is created automatically.Columns are commonly created as follows:
col=Column((module_name, table_name), column_name)
Alternatively:
tab=Table(module_name, table_name) col=Column(tab, column_name)
-
column_name
¶ The column’s name.
-
module_name
¶ Short-hand for
table.module_name
.
-
table_name
¶ Short-hand for
table.table_name
.
-
-
class
exos.api.cmfrontend.
Request
(op=2, outer_join=False, bulk=1, order='FIFO')[source]¶ Represent a CM Request. It identifies the requested fields, the source for each field, and any required parameters and indexes. A Request instance can be sent as an operation to
Cursor.execute()
. On execute(), the Request will be validated to ensure it is properly populated.InterfaceError
is raised if it is not.Request instances must be created via the
request()
method.-
outer_join
¶ If True, we’ll perform a “left outer join”. If False, the default, we’ll perform an “inner join”. See
request()
for more information.
-
op
¶ Either
CM_OP_GET
orCM_OP_SET
.
-
method
¶
-
tables
¶ List of tables encountered while building this request. Tables are not added explicitly, but discovered as fields, indexes, and params are added.
-
main_table
¶ The main table in this request, which will be used to drive the request when interacting with CM. It is arbitrarily taken as the first table encountered while building the request, otherwise
None
.
-
fields
¶ Ordered list of fields that will be included in the response. This is a mapping from a user-defined label to the fields’s data source, typically an instance of
Column
. Fields can be added to the request viaadd_field()
.
-
indexes
¶ Mapping from Table to a list of indexes found within that table. Each index is an instance of
Column
. Indexes must be identified by the client and are added to the request viaadd_index()
. When the Request is validated, at least one index must exist for each table. Indexes are not included in the response, unless the Column was also passed toadd_field()
.
-
params
¶ List of request parameters. This is a mapping from a
Column
instance to the parameter’s value, typically a constant, but, in the case of a join, could also be another Column. The value may also beNone
, indicating that a constant value will be passed on execute().Parameters are added to the request via
add_param()
.
-
add_index
(index_column)[source]¶ Identify an index Column. CM requires an index for each table so that it can getnext through the rows of a table. A client must identify which Columns are indexes.
index_column must be an instance of
Column
or a tuple thatColumn
knows how to handle.
-
add_param
(param_column, param_value=None)[source]¶ Identify a parameter Column. On a GET, parameters are typically filters or join conditions. On a SET, they are typically updated field values. Parameters are passed to CM “as is” with the expectation that the client and the module know how to talk to each other.
Not all Columns can be parameters. On a GET, CM supports only a subset of Columns as filters. On a SET, not all Columns are writeable. Again, it is assumed the client and module know how to talk to each other.
param_column must be an instance of
Column
or a tuple thatColumn
knows how to handle.param_value can be any of the following:
None
. This indicates a constant value will be passed onCursor.execute()
.- A constant. Same as
None
, except that the value is provided now instead of onCursor.execute()
. - Another
Column
. This builds a join condition where the two columns are joined with an equals.
param_value constants are stringified with the str() function each time an XML request is sent to the CM backend. As such, a dynamic param_value is possible by implementing the value’s __str__() method.
-
add_field
(field_label, field_source)[source]¶ Identify a field in the response. Fields are kept in an ordered list, so the response’s order will match the order in which the fields were added.
field_label is the string that will be used to identify the field in the response. It is arbitrary and user-defined.
field_source indicates how the field’s value will be retrieved. It can be any of the following:
- An instance of
Column
. In this case, the data source is CM and the given Column will be retrieved. - A callable. Reserved for future. For now, an exception is thrown. In the future, a callable will allow a field’s value to be derived, perhaps from other field values.
- An instance of any other class. The field source is a literal and the string version will be echoed back as the field’s value.
- An instance of
-
set_vr_name
(vr)[source]¶ Set the VR context for this Request. It will override the Cursor’s VR context. See
Cursor.vr_name
.
-
Row¶
-
class
exos.api.cmfrontend.
Row
(rowid, op_status)[source]¶ Represent a row of response from CM. Instances of Row are returned by
Cursor.fetchrow()
,Cursor.fetchrows()
, andCursor.iterrow()
.PEP-249 defines responses as arrays of values. The cmfrontend module additionally provides the Row object to provide a richer interface into the data returned by CM.
-
rowid
¶ This row’s ID. Matches up with
Cursor.rownumber
.
-
opMsg
¶ Any message returned by CM or
None
.
-
field_values
¶ Dict of field values in the Row. This is a mapping from the field’s label to the fields’s value.
-
Errors¶
The request cannot be processed because the module is unavailable. This may be a temporary condition. The
when_ready()
method may be used to be notified when the condition clears.This is an
OperationalError
.The module that was unavailable.
Call the given callback when the module might have become available or the timeout is reached. At this point, it’s safe to try the request again, but it might also fail again.
If a callback is not provided, the caller will be blocked instead.
PEP-249 Errors¶
Error classes as defined and required by PEP-249.