API Reference¶
mortar_rdb¶
- mortar_rdb.declarative_base(**kw)¶
Return a
Base
as would be returned bydeclarative_base()
.Only one
Base
will exist for each combination of parameters that this function is called with. If it is called with the same combination of parameters more than once, subsequent calls will return the existingBase
.This method should be used so that even if more than one package used by a project defines models, they will all end up in the same
MetaData
instance and all have the same declarative registry.
- mortar_rdb.drop_tables(engine)¶
Drop all the tables in the database attached to by the supplied engine.
As many foreign key constraints as possible will be dropped first making this quite brutal!
- mortar_rdb.get_session(name='')¶
Return a
Session
instance from the current registry as registered with the supplied name.
- mortar_rdb.register_session(url=None, name='', engine=None, echo=None, transactional=True, scoped=True, twophase=True)¶
Create a
Session
class and register it for later use.Generally, you’ll only need to pass in a
SQLAlchemy
connection URL. If you want to register multiple sessions for a particular application, then you should name them. If you want to provide specific engine configuration, then you can pass in anEngine
instance. In that case, you must not pass in a URL.- Parameters:
echo – If True, then all SQL will be echoed to the python logging framework. This option cannot be specified if you pass in an engine.
scoped – If True, then
get_session()
will return a distinct session for each thread that it is called from but, within that thread, it will always return the same session. If it is False, every call toget_session()
will return a new session.transactional –
If True, a
SQLAlchemy
extension will be used that that enables thetransaction
package to manage the lifecycle of the SQLAlchemy session (eg:begin()
/commit()
/rollback()
). This can only be done when scoped sessions are used.If False, you will need to make sure you call
begin()
/commit()
/rollback()
, as appropriate, yourself.twophase – By default two-phase transactions are used where supported by the underlying database. Where this causes problems, single-phase transactions can be used for all engines by passing this parameter as False.
mortar_rdb.controlled¶
When a database is used, it’s essential that code using the database only interacts with a database that is of the form it expects. A corollary of that is that it is important to be able to update the structure of a database from the form expected by one version of the code to that expected by another version of the code.
mortar_rdb.controlled
aims to facilitate this along with providing
a command line harness for creating necessary tables within a
database, emptying out a non-production database and upgrading a
database to a new structure where SQLAlchemy
is
used.
Packages, Models and Tables¶
SQLAlchemy
uses Table
objects that
are mapped to one or more model classes. These objects are defined
within python packages.
Configurations¶
A single database may contain tables that are defined in more that one package. For example, an authentication package may contain some table definitions for storing users and their permissions. That package may be used by an application which also contains a package that defines its own tables.
A Config
is a way of expressing
which tables should be expected in a database.
In general, it is recommended that a
Config
is defined once, in whatever
package ‘owns’ a particular database. For example, an application may
define a configuration for its own tables and those of any packages on
which it relies, such as the hypothetical authentication package
described above. If another application wants to use this
application’s database, it can import the configuration and check that
the database structure matches that expected by the code it is
currently using.
- class mortar_rdb.controlled.Config(*sources)¶
A configuration for a particular database to allow control of the schema of that database.
- Parameters:
sources – The
Source
instances from which to create this configuration.
- class mortar_rdb.controlled.Scripts(url, config, failsafe)¶
A command-line harness for performing schema control functions on a database. You should instantiate this in a small python script and call it when the script is run as a command, eg:
from mortar_rdb.controlled import Scripts from sample.model import config scripts = Scripts('sqlite://', config, True) if __name__=='__main__': script()
Writing the script in this style also allows
scripts
to be used as a :mod:setuptools entry point.- Parameters:
url – The
SQLAlchemy
url to connect to the database to be managed. If this isn’t known at the time when this class is instantiated, then useNone
.config – A
Config
instance describing the schema of the database to be managed.failsafe – A boolean value that should be
True
if it’s okay for the database being managed to have all its tables dropped. For obvious reasons, this should beFalse
when managing your production database.
- create()¶
Create all the tables in the configuration in the database
- drop()¶
Drop all tables in the database
- class mortar_rdb.controlled.Source(*tables)¶
A collection of tables that should have their versioning managed together. This usually means they originate from one package.
- Parameters:
tables – A sequence of
Table
objects that contain all the tables that will be managed by the repository in this Source.
- mortar_rdb.controlled.scan(package, tables=())¶
Scan a package or module and return a
Source
containing the tables from any declaratively mapped models found, anyTable
objects explicitly passed in and thesqlalchemy-migrate
repository contained within the package.Note
While the package parameter is passed as a string, this will be resolved into a module or package object. It is not a distribution name, although the two are often very similar.
- Parameters:
package – A dotted path to the package to be scanned for
Table
objects.tables – A sequence of
Table
objects to be added to the returnedSource
. Any tables not created as part of declaratively mapping a class will need to be passed in using this sequence asscan()
cannot sensibly scan for these objects.
mortar_rdb.testing¶
Helpers for unit testing when using mortar_rdb
- class mortar_rdb.testing.TestingBase¶
This is a helper class that can either be used to make
declarative_base()
return a new, emptyBase
for testing purposes.If writing a suite of unit tests, this can be done as follows:
from mortar_rdb.testing import TestingBase from unittest import TestCase class YourTestCase(TestCase): def setUp(self): self.tb = TestingBase() def tearDown(self): self.tb.restore()
If you need a fresh
Base
for a short section of Python code,TestingBase
can also be used as a context manager:with TestingBase(): base = declarative_base() # your test code here
- mortar_rdb.testing.register_session(url=None, name='', engine=None, echo=False, transactional=True, scoped=True, config=None, metadata=None)¶
This will create a
Session
class for testing purposes and register it for later use.The calling parameters mirror those of
mortar_rdb.register_session()
but if neither url nor engine is specified then:The environment will be consulted for a variable called
DB_URL
. If found, that will be used for the url parameter.If url is still None, an implicit url of
sqlite://
will be used.
If a
Config
is passed in then, once any existing content in the database has been removed, any tables controlled by that config will be created.If a
MetaData
instance is passed in, then all tables within it will be created.Unlike the non-testing
register_session
, this will also return an instance of the registered session.Warning
No matter where the url or engine come from, the entire contents of the database they point at will be destroyed!
mortar_rdb.interfaces¶
Internal interface definitions. Unless you’re doing something pretty special, you don’t need to know about these.
- interface mortar_rdb.interfaces.ISession¶
A marker interface for SQLAlchemy Sessions. This is so that we can register factories that return them.
- interface mortar_rdb.interfaces.ISequence¶
An interface for sequence utility impementations. A sequence is a non-repeating, always-incrementing sequence of integers.
Implementations of this interface will be instantiated once and then have their
next()
method called often.