Skip to content

Commit

Permalink
Merge 0399063 into a9c1aeb
Browse files Browse the repository at this point in the history
  • Loading branch information
Anthchirp committed Jun 26, 2018
2 parents a9c1aeb + 0399063 commit 013360d
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 5 deletions.
24 changes: 24 additions & 0 deletions docs/api.rst
Expand Up @@ -2,7 +2,31 @@
API
===

Connecting to ISPyB
===================

.. automodule:: ispyb
:members:
:show-inheritance:

Accessing records using the object model
========================================

The connection object offers the following accessor functions to get
object-like representations of database entries:

.. autoclass:: ispyb.model.interface.ObjectModelMixIn
:members:

DataCollection
==============

.. automodule:: ispyb.model.datacollection
:members:

ProcessingJob
=============

.. automodule:: ispyb.model.processingjob
:members:

2 changes: 1 addition & 1 deletion docs/conf.py
Expand Up @@ -83,7 +83,7 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
html_theme = 'classic'

# Theme options are theme-specific and customize the look and feel of a
# theme further. For a list of options available for each theme, see the
Expand Down
8 changes: 7 additions & 1 deletion ispyb/__init__.py
Expand Up @@ -11,7 +11,13 @@
_log = logging.getLogger('ispyb')

def open(configuration_file):
'''Create an ISPyB connection using settings from a configuration file.'''
'''Create an ISPyB connection using settings from a configuration file.
This can be used either as a function call or as a context manager.
:param configuration_file: Full path to a file containing database
credentials
:return: ISPyB connection object
'''
config = configparser.RawConfigParser(allow_no_value=True)
if not config.read(configuration_file):
raise AttributeError('No configuration found at %s' % configuration_file)
Expand Down
2 changes: 2 additions & 0 deletions ispyb/interface/acquisition.py
Expand Up @@ -28,4 +28,6 @@ def upsert_data_collection(self, cursor, values):
def get_data_collection(self, dcid):
'''Return a DataCollection object representing the information about the
selected data collection'''
import warnings
warnings.warn("Object model getter call on the data area is deprecated and will be removed in the next release. Call the function on connection object instead.", DeprecationWarning)
return ispyb.model.datacollection.DataCollection(dcid, self)
6 changes: 5 additions & 1 deletion ispyb/interface/connection.py
@@ -1,9 +1,13 @@
import abc
import ispyb.interface.factory
import ispyb.model.interface

ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) # compatible with Python 2 *and* 3

class IF(ABC, ispyb.interface.factory.factory_mixin):
class IF(
ABC,
ispyb.interface.factory.FactoryMixIn,
ispyb.model.interface.ObjectModelMixIn):
'''ISPyB connection interface definition object.'''

@abc.abstractmethod
Expand Down
2 changes: 1 addition & 1 deletion ispyb/interface/factory.py
Expand Up @@ -2,7 +2,7 @@

import importlib

class factory_mixin():
class FactoryMixIn():
def _get_data_area(self, module, classname):
'''Helper function to instantiate a data area or return a cached instance.'''
if hasattr(self, '_cache_' + module):
Expand Down
2 changes: 2 additions & 0 deletions ispyb/interface/processing.py
Expand Up @@ -25,4 +25,6 @@ def get_quality_indicators_params(self):

def get_processing_job(self, jobid):
'''Return a ProcessingJob object representing the information about the selected processing job'''
import warnings
warnings.warn("Object model getter call on the data area is deprecated and will be removed in the next release. Call the function on connection object instead.", DeprecationWarning)
return ispyb.model.processingjob.ProcessingJob(jobid, self)
64 changes: 64 additions & 0 deletions ispyb/model/datacollection.py
Expand Up @@ -17,6 +17,7 @@ def __init__(self, dcid, db_area, preload=None):
:return: A DataCollection object representing the database entry for
the specified DataCollectionID
'''
self._cache_group = None
self._db = db_area
self._dcid = int(dcid)
if preload:
Expand All @@ -31,6 +32,13 @@ def dcid(self):
'''Returns the DataCollectionID.'''
return self._dcid

@property
def group(self):
'''Returns a DataCollectionGroup object'''
if self._cache_group is None:
self._cache_group = DataCollectionGroup(self.dcgid, self._db.conn)
return self._cache_group

def __repr__(self):
'''Returns an object representation, including the DataCollectionID,
the database connection interface object, and the cache status.'''
Expand All @@ -48,12 +56,68 @@ def __str__(self):
'DataCollection #{0.dcid}',
' Started : {0.time_start}',
' Finished : {0.time_end}',
' DC group : {0.dcgid}',
))).format(self)

for key, internalkey in (
('dcgid', 'groupId'),
('time_start', 'startTime'),
('time_end', 'endTime'),
('image_count', 'noImages'),
('image_start_number', 'startImgNumber'),
):
setattr(DataCollection, key, property(lambda self, k=internalkey: self._data[k]))

class DataCollectionGroup(ispyb.model.DBCache):
'''An object representing a DataCollectionGroup database entry. The object
lazily accesses the underlying database when necessary and exposes record
data as python attributes.
'''

def __init__(self, dcgid, db_conn, preload=None):
'''Create a DataCollectionGroup object for a defined DCGID. Requires
a database connection object exposing further data access methods.
:param dcgid: DataCollectionGroupID
:param db_conn: ISPyB database connection object
:return: A DataCollectionGroup object representing the database entry for
the specified DataCollectionGroupID
'''
self._cache_gridinfo = None
self._db = db_conn
self._dcgid = int(dcgid)
if preload:
self._data = preload

def reload(self):
'''Load/update information from the database.'''
raise NotImplementedError("TODO: Loading not yet supported")

@property
def dcgid(self):
'''Returns the DataCollectionGroupID.'''
return self._dcgid

@property
def gridinfo(self):
'''Returns a GridInfo object.'''
if self._cache_gridinfo is None:
self._cache_gridinfo = GridInfo(self.dcgid, self._db)
return self._cache_gridinfo

def __repr__(self):
'''Returns an object representation, including the DataCollectionGroupID,
the database connection interface object, and the cache status.'''
return '<DataCollectionGroup #%d (%s), %r>' % (
self._dcgid,
'cached' if self.cached else 'uncached',
self._db
)

def __str__(self):
'''Returns a pretty-printed object representation.'''
if not self.cached:
return 'DataCollectionGroup #%d (not yet loaded from database)' % self._dcgid
return ('\n'.join((
'DataCollectionGroup #{0.dcgid}',
))).format(self)
49 changes: 49 additions & 0 deletions ispyb/model/gridinfo.py
@@ -0,0 +1,49 @@
from __future__ import absolute_import, division, print_function

import ispyb.model

class GridInfo(ispyb.model.DBCache):
'''An object representing a GridInfo database entry. The object
lazily accesses the underlying database when necessary and exposes record
data as python attributes.
'''

def __init__(self, dcgid, db_conn, preload=None):
'''Create a GridInfo object for a defined DCGID. Requires
a database connection object exposing further data access methods.
:param dcgid: DataCollectionGroupID
:param db_conn: ISPyB database connection object
:return: A GridInfo object representing the database entry for
the specified DataCollectionGroupID
'''
self._db = db_conn
self._dcgid = int(dcgid)
if preload:
self._data = preload

def reload(self):
'''Load/update information from the database.'''
raise NotImplementedError('TODO: Not implemented yet')

@property
def dcgid(self):
'''Returns the DataCollectionGroupID.'''
return self._dcgid

def __repr__(self):
'''Returns an object representation, including the DataCollectionGroupID,
the database connection interface object, and the cache status.'''
return '<GridInfo #%d (%s), %r>' % (
self._dcgid,
'cached' if self.cached else 'uncached',
self._db
)

def __str__(self):
'''Returns a pretty-printed object representation.'''
if not self.cached:
return 'GridInfo #%d (not yet loaded from database)' % self._dcid
return ('\n'.join((
'GridInfo #{0.dcgid}',
))).format(self)
31 changes: 31 additions & 0 deletions ispyb/model/interface.py
@@ -0,0 +1,31 @@
from __future__ import absolute_import, division, print_function

import ispyb.model.datacollection
import ispyb.model.processingjob

class ObjectModelMixIn():
'''Object model accessor functions for Connector classes.'''

def get_data_collection(self, dcid):
'''Return a DataCollection object representing the information
about the selected data collection'''
return ispyb.model.datacollection.DataCollection(
dcid,
self.mx_acquisition,
)

def get_data_collection_group(self, dcgid):
'''Return a DataCollectionGroup object representing the information
about the selected data collection group'''
return ispyb.model.datacollection.DataCollectionGroup(
dcgid,
self,
)

def get_processing_job(self, jobid):
'''Return a ProcessingJob object representing the information
about the selected processing job.'''
return ispyb.model.processingjob.ProcessingJob(
jobid,
self.mx_processing,
)
4 changes: 3 additions & 1 deletion tests/test_mxacquisition.py
Expand Up @@ -37,8 +37,10 @@ def test_mxacquisition_methods(testconfig):
rs = mxacquisition.retrieve_data_collection_main(id1)
assert rs[0]['groupId'] == dcgid

dc = mxacquisition.get_data_collection(id1)
dc = conn.get_data_collection(id1)
assert dc.image_count == 360
assert dc.dcgid == dcgid
assert dc.group.dcgid == dcgid

params = mxacquisition.get_image_params()
params['parentid'] = id1
Expand Down

0 comments on commit 013360d

Please sign in to comment.