qm :: test :: database :: Database :: Class Database
[hide private]
[frames] | no frames]

Class Database

source code

         object --+    
                  |    
extension.Extension --+
                      |
                     Database
Known Subclasses:

A 'Database' stores tests, testsuites, and resources.

A 'Database' has two primary functions:

1. Test storage and retrieval.

   Every test has a unique name, called a "test id". When a new 
   test is created, the 'Database' is responsible for writing that
   test to permanent storage.  Later, QMTest will request the test 
   by providing the database with the test id.  The database must
   retrieve the test from permanent storage.

   QMTest does not put any restrictions on *how* tests are stored.
   The default database implementation uses XML to store tests,
   but any storage format will do.

2. Test enumeration.

   The 'Database' can tell QMTest what tests are stored in the
   database.  QMTest uses this information in its graphical user
   interface to show the user what tests exist.
   
A 'Database' stores testsuites and resources in addition to tests.
The names for tests, testsuites, and resources are all "labels".  A
label is a special kind of string that is designed to be easily
convertible to a file name.  For more information, see the
'qm.label' module.  The namespaces for tests, testsuites, and
resources are all distinct.  For example, it is OK to have a test
with the same name as a testsuite.

Every 'Database' is associated with a particular directory on the
local machine.  In most cases, the 'Database' will store all the
files it needs within this directory.

Every 'Database' has an associated 'AttachmentStore'.  An
'AttachmentStore' is responsible for storing the attachments
associated with tests.  See the module 'qm.attachment' for more
information about 'AttachmentStore'.

'Database' is an abstract class.

You can extend QMTest by providing your own database implementation.
One reason to do this is that you may want to store tests in a
format different from the XML format that QMTest uses by default.
For example, if you are testing a compiler, you might want to
represent each test as a source file.  Or, if you are testing a
SQL database, you might want to represent each test as two files:
one containing SQL commands to run the test, and one containing
the output you expect.

Another reason to provide your own database implementation is that
you might want to store tests on a remote location.  For example,
suppose you wanted to allow multiple users to access the same 
central test database.  You could create a test database that
created and retrieved tests by communicating with the central
server.

To create your own database implementation, you must create a Python
class derived (directly or indirectly) from 'Database'.  The
documentation for each method of 'Database' indicates whether you
must override it in your database implementation.  Some methods may
be overridden, but do not need to be.  You might want to override
such a method to provide a more efficient implementation, but QMTest
will work fine if you just use the default version.

If QMTest calls a method on a database and that method raises an
exception that is not caught within the method itself, QMTest will
catch the exception and continue processing.  Therefore, methods
here only have to handle exceptions themselves if that is necessary
to maintain the integrity of the database.

A single 'Database' may be accessed by multiple threads
simultaneously.  Therefore, you must take appropriate steps to
ensure thread-safe access to shared data.

Nested Classes [hide private]

Inherited from extension.Extension: Type, __metaclass__

Instance Methods [hide private]
 
__init__(self, path, arguments=None, **args)
Construct a 'Database'.
source code
 
IsValidLabel(self, label, is_component=1)
Return true if 'label' is valid.
source code
 
JoinLabels(self, *labels)
Join the 'labels' together.
source code
 
SplitLabel(self, label)
Split the label into a pair '(directory, basename)'.
source code
 
SplitLabelLeft(self, label)
Split the label into a pair '(parent, subpath)'.
source code
 
GetLabelComponents(self, label)
Return all of the component directories of 'label'.
source code
 
GetExtension(self, id)
Return the extension object named 'id'.
source code
 
GetExtensions(self, directory, scan_subdirs)
Return the extensions in 'directory'.
source code
 
RemoveExtension(self, id, kind)
Remove the extension 'id' from the database.
source code
 
WriteExtension(self, id, extension)
Store 'extension' in the database, using the name 'id'.
source code
 
GetTest(self, test_id)
Return the 'TestDescriptor' for the test named 'test_id'.
source code
 
HasTest(self, test_id)
Check whether or not the database has a test named 'test_id'.
source code
 
GetTestIds(self, directory='', scan_subdirs=1)
Return all test IDs that begin with 'directory'.
source code
 
GetSuite(self, suite_id)
Return the 'Suite' for the suite named 'suite_id'.
source code
 
HasSuite(self, suite_id)
Check whether or not the database has a suite named 'suite_id'.
source code
 
GetSuiteIds(self, directory='', scan_subdirs=1)
Return all suite IDs that begin with 'directory'.
source code
 
GetResource(self, resource_id)
Return the 'ResourceDescriptor' for the resource 'resouce_id'.
source code
 
HasResource(self, resource_id)
Check whether or not the database has a resource named 'resource_id'.
source code
 
GetResourceIds(self, directory='', scan_subdirs=1)
Return all resource IDs that begin with 'directory'.
source code
 
GetIds(self, kind, directory='', scan_subdirs=1)
Return all IDs of the indicated 'kind' that begin with 'directory'.
source code
 
GetItem(self, kind, item_id)
Return the item of the indicated 'kind' with indicated 'item_id'.
source code
 
GetSubdirectories(self, directory)
Return the immediate subdirectories of 'directory'.
source code
 
GetPath(self)
Return the directory containing the database.
source code
 
GetConfigurationDirectory(self)
Return the directory containing configuration information.
source code
 
GetAttachmentStore(self)
Returns the 'AttachmentStore' associated with the database.
source code
 
GetClassPaths(self)
Return directories to search for test and resource classes.
source code
 
GetTestClassNames(self)
Return the kinds of tests that the database can store.
source code
 
GetResourceClassNames(self)
Return the kinds of resources that the database can store.
source code
 
ExpandIds(self, ids)
Expand test and suite IDs into test IDs.
source code
 
IsModifiable(self)
Returns true iff this database is modifiable.
source code

Inherited from extension.Extension: GetClassName, GetExplicitArguments, MakeDomDocument, MakeDomElement, Write, __getattr__

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Class Variables [hide private]
  arguments = [<<class 'qm.fields.TextField'> label_class>, <<cl...
A list of the arguments to the extension class.
  RESOURCE = 'resource'
  SUITE = 'suite'
  TEST = 'test'
  ITEM_KINDS = ['resource', 'suite', 'test']
The kinds of items that can be stored in a 'Database'.
  _item_exceptions = {'resource': <class 'qm.test.database.NoSuc...
The exceptions to be raised when a particular item cannot be found.
  _is_generic_database = False
True if this database implements 'GetExtension' as a primitive.
  kind = 'database'
The 'Extension' kind.
  _argument_dictionary = {'label_class': <<class 'qm.fields.Text...
A map from argument names to 'Field' instances.
  _argument_list = [<<class 'qm.fields.BooleanField'> modifiable...
A list of all the 'Field's in this class.
  label_class = 'python_label.PythonLabel'
  modifiable = 'true'
Properties [hide private]

Inherited from object: __class__

Method Details [hide private]

__init__(self, path, arguments=None, **args)
(Constructor)

source code 

Construct a 'Database'.

'path' -- A string containing the absolute path to the directory containing the database.

'arguments' -- A dictionary mapping attribute names to values. The use of this parameter is deprecated. Use keyword arguments instead.

Derived classes must call this method from their own '__init__' methods. Every derived class must have an '__init__' method that takes the path to the directory containing the database as its only argument. The path provided to the derived class '__init__' function will always be an absolute path.

Overrides: object.__init__

IsValidLabel(self, label, is_component=1)

source code 

Return true if 'label' is valid.

'label' -- A string that is being considered as a label.

'is_component' -- True if the string being tested is just a single component of a label path.

returns -- True if 'label' is a valid name for entities in this database.

JoinLabels(self, *labels)

source code 

Join the 'labels' together.

'labels' -- A sequence of strings corresponding to label components.

returns -- A string containing the complete label.

SplitLabel(self, label)

source code 

Split the label into a pair '(directory, basename)'.

returns -- A pair of strings '(directory, basename)'.

SplitLabelLeft(self, label)

source code 

Split the label into a pair '(parent, subpath)'. This is the same operation as SplitLabel, except the split occurs at the leftmost separator, not the rightmost, and a single-component label comes back in the parent slot.

returns -- A pair of strings '(parent, subpath)'.

GetLabelComponents(self, label)

source code 

Return all of the component directories of 'label'.

'label' -- A string naming an entity in the database.

returns -- A list of strings. The first string is the first directory in 'label'; the last string is the basename.

GetExtension(self, id)

source code 

Return the extension object named 'id'.

'id' -- The label for the extension.

returns -- The instance of 'Extension' with the indicated name, or 'None' if there is no such entity.

Database classes should override this method. For backwards compatibility, this base class implements this generic method in terms of the special-purpose methods 'GetTest()' and 'GetResource()'. Only if _is_generic_database is True are these implemented in terms of 'GetExtension()'.

GetExtensions(self, directory, scan_subdirs)

source code 

Return the extensions in 'directory'.

'directory' -- The name of a directory.

'scan_subdirs' -- True if (and only if) subdirectories of 'directory' should be scanned.

returns -- A dictionary mapping labels to 'Extension' instances. The dictionary contains all extensions in 'directory', and, if 'scan_subdirs' is true, its subdirectories.

RemoveExtension(self, id, kind)

source code 

Remove the extension 'id' from the database.

'id' -- A label for the 'Extension' instance stored in the database.

'kind' -- The kind of 'Extension' stored with the given 'id'.

WriteExtension(self, id, extension)

source code 

Store 'extension' in the database, using the name 'id'.

'id' -- A label for the 'extension'.

'extension' -- An instance of 'Extension'.

The 'extension' is stored in the database. If there is a previous item in the database with the same id, it is removed and replaced with 'extension'. Some databases may not be able to store all 'Extension' instances; those database must throw an exception when an attempt is made to store such an 'extension'.

GetTest(self, test_id)

source code 

Return the 'TestDescriptor' for the test named 'test_id'.

'test_id' -- A label naming the test.

returns -- A 'TestDescriptor' corresponding to 'test_id'.

raises -- 'NoSuchTestError' if there is no test in the database named 'test_id'.

HasTest(self, test_id)

source code 

Check whether or not the database has a test named 'test_id'.

'test_id' -- A label naming the test.

returns -- True if and only if the database contains a test named 'test_id'. If this function returns true, 'GetTest' will usually succeed. However, they may be circumstances where 'HasTest' returns true and 'GetTest' does not succeed. For example, someone might remove a critical file from the database between the time that 'HasTest' is called and the time that 'GetTest' is called.

Derived classes may override this method.

GetTestIds(self, directory='', scan_subdirs=1)

source code 

Return all test IDs that begin with 'directory'.

'directory' -- A label indicating the directory in which to begin the search.

'scan_subdirs' -- True if (and only if) subdirectories of 'directory' should be scanned.

'returns' -- A list of all tests located within 'directory', as absolute labels.

GetSuite(self, suite_id)

source code 

Return the 'Suite' for the suite named 'suite_id'.

'suite_id' -- A label naming the suite.

returns -- An instance of 'Suite' (or a derived class of 'Suite') corresponding to 'suite_id'.

raises -- 'NoSuchSuiteError' if there is no test in the database named 'test_id'.

All databases must have an implicit suite called '' that contains all tests in the database. More generally, for each directory in the database, there must be a corresponding suite that contains all tests in that directory and its subdirectories.

HasSuite(self, suite_id)

source code 

Check whether or not the database has a suite named 'suite_id'.

'suite_id' -- A label naming the suite.

returns -- True if and only if the database contains a suite named 'suite_id'. If this function returns true, 'GetSuite' will usually succeed. However, they may be circumstances where 'HasSuite' returns true and 'GetSuite' does not succeed. For example, someone might remove a critical file from the database between the time that 'HasSuite' is called and the time that 'GetSuite' is called.

All databases must have an implicit suite called "" that contains all tests in the database. More generally, for each directory in the database, there must be a corresponding suite that contains all tests in that directory and its subdirectories.

Derived classes may override this method.

GetSuiteIds(self, directory='', scan_subdirs=1)

source code 

Return all suite IDs that begin with 'directory'.

'directory' -- A label indicating the directory in which to begin the search.

'scan_subdirs' -- True if (and only if) subdirectories of 'directory' should be scanned.

'returns' -- A list of all suites located within 'directory', as absolute labels.

GetResource(self, resource_id)

source code 

Return the 'ResourceDescriptor' for the resource 'resouce_id'.

'resource_id' -- A label naming the resource.

returns -- A 'ResourceDescriptor' corresponding to 'resource_id'.

raises -- 'NoSuchResourceError' if there is no resource in the database named 'resource_id'.

HasResource(self, resource_id)

source code 

Check whether or not the database has a resource named 'resource_id'.

'resource_id' -- A label naming the resource.

returns -- True if and only if the database contains a resource named 'resource_id'. If this function returns true, 'GetResource' will usually succeed. However, they may be circumstances where 'HasResource' returns true and 'GetResource' does not succeed. For example, someone might remove a critical file from the database between the time that 'HasResource' is called and the time that 'GetResource' is called.

Derived classes may override this method.

GetResourceIds(self, directory='', scan_subdirs=1)

source code 

Return all resource IDs that begin with 'directory'.

'directory' -- A label indicating the directory in which to begin the search.

'scan_subdirs' -- True if (and only if) subdirectories of 'directory' should be scanned.

'returns' -- A list of all resources located within 'directory', as absolute labels.

GetIds(self, kind, directory='', scan_subdirs=1)

source code 

Return all IDs of the indicated 'kind' that begin with 'directory'.

'kind' -- One of the 'ITEM_KINDS'.

'directory' -- A label indicating the directory in which to begin the search.

'scan_subdirs' -- True if (and only if) subdirectories of 'directory' should be scanned.

returns -- A list of all items of the indicated 'kind' located within 'directory', as absolute labels.

Derived classes may override this method.

GetItem(self, kind, item_id)

source code 

Return the item of the indicated 'kind' with indicated 'item_id'.

'kind' -- One of the 'ITEM_KINDS'.

'item_id' -- The name of the item.

returns -- If 'kind' is 'Database.TEST' or 'Database.RESOURCE', returns a test descriptor or resource descriptor, respectively. If 'kind' is 'Database.SUITE', returns a 'Suite'.

Derived classes may override this method.

GetSubdirectories(self, directory)

source code 

Return the immediate subdirectories of 'directory'.

'directory' -- A label indicating a directory in the database.

returns -- A sequence of (relative) labels indictating the immediate subdirectories of 'directory'. For example, if "a.b" and "a.c" are directories in the database, this method will return "b" and "c" given "a" as 'directory'.

Derived classes may override this method.

GetPath(self)

source code 

Return the directory containing the database.

returns -- A string containing the absolute path to the directory containing the database.

Derived classes must not override this method.

GetConfigurationDirectory(self)

source code 

Return the directory containing configuration information.

returns -- The directory containing configuration information for the database.

Derived classes must not override this method.

GetAttachmentStore(self)

source code 

Returns the 'AttachmentStore' associated with the database.

returns -- The 'AttachmentStore' containing the attachments associated with tests and resources in this database.

Derived classes may override this method.

GetClassPaths(self)

source code 

Return directories to search for test and resource classes.

returns -- A sequence of strings. Each string is a directory that should be searched to locate test and resource classes. The directories will be searched in the order they appear. QMTest will search other directories (like those in the 'QMTEST_CLASS_PATH' environment variable) in addition to these directories.

For a given database, this method should always return the same value; callers are permitted to cache the value returned.

Derived classes may override this method. The sequence returned by the derived class need not be a superset of the value returned by the default implementation (but probably should be).

GetTestClassNames(self)

source code 

Return the kinds of tests that the database can store.

returns -- A sequence of strings. Each string names a class, including the containing module. Only classes of these types can be stored in the database.

Derived classes may override this method. The default implementation allows all available test classes, but the derived class may allow only a subset.

GetResourceClassNames(self)

source code 

Return the kinds of resources that the database can store.

returns -- A sequence of strings. Each string names a class, including the containing module. Only resources of these types can be stored in the database.

Derived classes may override this method. The default implementation allows all available resource classes, but the derived class may allow only a subset.

ExpandIds(self, ids)

source code 

Expand test and suite IDs into test IDs.

'ids' -- A sequence of IDs of tests and suites, which may be mixed together.

returns -- A pair 'test_ids, suite_ids'. 'test_ids' is a sequence of test IDs including all test IDs mentioned in 'ids' plus all test IDs obtained from recursively expanding suites included in 'ids'. 'suite_ids' is the set of IDs of suites included directly and indirectly in 'ids'.

raises -- 'ValueError' if an element in 'id' is neither a test or suite ID. The exception argument is the erroneous element.

IsModifiable(self)

source code 

Returns true iff this database is modifiable.

returns -- True iff this database is modifiable. If the database is modifiable, it supports operatings like 'Write' that make changes to the structure of the databaes itself. Otherwise, the contents of the database may be viewed, but not modified.


Class Variable Details [hide private]

arguments

A list of the arguments to the extension class.

Each element of this list should be an instance of 'Field'. The 'Field' instance describes the argument.

Derived classes may redefine this class variable. However, derived classes should not explicitly include the arguments from base classes; QMTest will automatically combine all the arguments found throughout the class hierarchy.

Value:
[<<class 'qm.fields.TextField'> label_class>,
 <<class 'qm.fields.BooleanField'> modifiable>]

_item_exceptions

The exceptions to be raised when a particular item cannot be found.

This map is indexed by the 'ITEM_KINDS'; the value indicates the exception class to be used when the indicated kind cannot be found.

Value:
{'resource': <class 'qm.test.database.NoSuchResourceError'>,
 'suite': <class 'qm.test.database.NoSuchSuiteError'>,
 'test': <class 'qm.test.database.NoSuchTestError'>}

_is_generic_database

True if this database implements 'GetExtension' as a primitive.

Databases should implement 'GetExtension' and then override '_is_generic_database', setting it to 'True'. However, legacy databases implemented 'GetTest', 'GetResource', and 'GetSuite' as primivites. These legacy databases should not override '_generic_database'.

Value:
False

_argument_dictionary

A map from argument names to 'Field' instances.

A map from the names of arguments for this class to the corresponding 'Field'.

Value:
{'label_class': <<class 'qm.fields.TextField'> label_class>,
 'modifiable': <<class 'qm.fields.BooleanField'> modifiable>}

_argument_list

A list of all the 'Field's in this class.

This list combines the complete list of 'arguments'. 'Field's appear in the order reached by a pre-order breadth-first traversal of the hierarchy, starting from the most derived class.

Value:
[<<class 'qm.fields.BooleanField'> modifiable>,
 <<class 'qm.fields.TextField'> label_class>]