Skip to content
Snippets Groups Projects
Commit acb1cd23 authored by kaloyane's avatar kaloyane
Browse files

[LMS-2332] further improvements

1) allow empty wells in the library template (no well sample will be created in openBIS)
2) handle Sanofi wellCode format (e.g. AC007 is translated to AC7)
3) bugfix: well rows start counting from 1 (not from 0)

SVN: 21946
parent d00e3431
No related branches found
No related tags found
No related merge requests found
import re
from ch.systemsx.cisd.common.mail import From from ch.systemsx.cisd.common.mail import From
from ch.systemsx.cisd.openbis.generic.shared.api.v1.dto import SearchCriteria from ch.systemsx.cisd.openbis.generic.shared.api.v1.dto import SearchCriteria
...@@ -98,14 +100,25 @@ class SanofiMaterial: ...@@ -98,14 +100,25 @@ class SanofiMaterial:
A data structure class holding compound materials as they exist in the Abase (Sanofi) database. A data structure class holding compound materials as they exist in the Abase (Sanofi) database.
""" """
def __init__(self, wellCode, materialCode, sanofiId, sanofiBatchId): def __init__(self, wellCode, materialCode, sanofiId, sanofiBatchId):
self.wellCode = wellCode self.wellCode = self.normalizeWellCode(wellCode)
self.materialCode = materialCode self.materialCode = materialCode
self.sanofiId = sanofiId self.sanofiId = sanofiId
self.sanofiBatchId = sanofiBatchId self.sanofiBatchId = sanofiBatchId
def normalizeWellCode(self, wellCode):
""" normalizes Sanofi wellCodes openBIS wellCodes e.g. AB007 to AB7 """
return re.sub("(?<=\w)(0+)(?=\d)", "", wellCode)
class PlateInitializer: class PlateInitializer:
ABASE_DATA_SOURCE = "abase-datasource" ABASE_DATA_SOURCE = "abase-datasource"
ABASE_QUERY = "TODO: this a query provided by Matt" ABASE_QUERY = """select
ptodwellreference WELL_CODE,
translate(objdbatchref,'{/:()+','{_____') MATERIAL_CODE,
objdbatchref ABASE_COMPOUND_BATCH_ID,
objdid ABASE_COMPOUND_ID,
olptid ABASE_PLATE_CODE
from sysadmin.plteobjd
where olptid = ?{1}"""
LIBRARY_TEMPLATE_PROPNAME = "LIBRARY_TEMPLATE" LIBRARY_TEMPLATE_PROPNAME = "LIBRARY_TEMPLATE"
...@@ -113,10 +126,10 @@ class PlateInitializer: ...@@ -113,10 +126,10 @@ class PlateInitializer:
NEGATIVE_CONTROL_TYPE = "NEGATIVE_CONTROL" NEGATIVE_CONTROL_TYPE = "NEGATIVE_CONTROL"
COMPOUND_WELL_TYPE = "COMPOUND_WELL" COMPOUND_WELL_TYPE = "COMPOUND_WELL"
COMPOUND_WELL_CONCENTRATION_PROPNAME = "CONCENTRATION" COMPOUND_WELL_CONCENTRATION_PROPNAME = "CONCENTRATION_M"
COMPOUND_WELL_MATERIAL_PROPNAME = "COMPOUND_BATCH" COMPOUND_WELL_MATERIAL_PROPNAME = "COMPOUND"
MATERIAL_TYPE = "COMPOUND_BATCH" MATERIAL_TYPE = "COMPOUND"
MATERIAL_ID_PROPNAME = "COMPOUND_ID" MATERIAL_ID_PROPNAME = "COMPOUND_ID"
MATERIAL_BATCH_ID_PROPNAME = "COMPOUND_BATCH_ID" MATERIAL_BATCH_ID_PROPNAME = "COMPOUND_BATCH_ID"
...@@ -125,9 +138,16 @@ class PlateInitializer: ...@@ -125,9 +138,16 @@ class PlateInitializer:
self.plate = plate self.plate = plate
self.plateCode = plate.getCode() self.plateCode = plate.getCode()
self.experimentId = plate.getExperiment().getExperimentIdentifier() self.experimentId = plate.getExperiment().getExperimentIdentifier()
def wellColumn(self, x):
numLetters = 26
if x < numLetters:
return chr(ord('A') + x)
else:
return self.wellColumn((x / numLetters) - 1) + self.wellColumn( x % numLetters)
def getWellCode(self, x, y): def getWellCode(self, x, y):
return chr(ord('A') + x) + str(y) return self.wellColumn(x) + str(y + 1)
def getPlateDimensions(self): def getPlateDimensions(self):
""" """
...@@ -146,14 +166,15 @@ class PlateInitializer: ...@@ -146,14 +166,15 @@ class PlateInitializer:
if plateHeight != len(tsvLines) : if plateHeight != len(tsvLines) :
raise RuntimeError("The geometry property of plate %(plateCode)s (height=%(plateHeight)s)" raise RuntimeError("The geometry property of plate %(plateCode)s (height=%(plateHeight)s)"
" does not agree with the value of the %(LIBRARY_TEMPLATE_PROPNAME)s" " does not agree with the value of the %(LIBRARY_TEMPLATE_PROPNAME)s"
" property in experiment %(experimentId)s (height=%(numLines)s)." % vars()) " property in experiment %(experimentId)s (height=%(numLines)s)." % vars(self))
for i in range(0, len(tsvLines)): for i in range(0, len(tsvLines)):
lineWidth = len(tsvLines[i]) lineWidth = len(tsvLines[i])
if plateWidth != lineWidth: if plateWidth != lineWidth:
raise RuntimeError("The geometry property of plate %(plateCode)s (width=%(plateWidth)s)" raise RuntimeError("The geometry property of plate %s (width=%s)"
" does not agree with the value of the %(LIBRARY_TEMPLATE_PROPNAME)s" " does not agree with the value of the %s"
" property in experiment %(experimentId)s (line=%(i)s, width=%(lineWidth)s)." % vars()) " property in experiment %s (line=%s, width=%s)." % \
(plateCode, plateWidth, self.LIBRARY_TEMPLATE_PROPNAME, self.experimentId, i, lineWidth))
def parseLibraryTemplate(self): def parseLibraryTemplate(self):
template = experiment.getPropertyValue(self.LIBRARY_TEMPLATE_PROPNAME) template = experiment.getPropertyValue(self.LIBRARY_TEMPLATE_PROPNAME)
...@@ -179,7 +200,7 @@ class PlateInitializer: ...@@ -179,7 +200,7 @@ class PlateInitializer:
In case the plate is not found in Abase return None. In case the plate is not found in Abase return None.
""" """
queryService = state.getDataSourceQueryService() queryService = state.getDataSourceQueryService()
queryResult = queryService.select(self.ABASE_DATA_SOURCE, self.ABASE_QUERY, [plate.code]) queryResult = queryService.select(self.ABASE_DATA_SOURCE, self.ABASE_QUERY, [self.plateCode])
sanofiMaterials = [] sanofiMaterials = []
for materialMap in list(queryResult): for materialMap in list(queryResult):
...@@ -240,7 +261,10 @@ class PlateInitializer: ...@@ -240,7 +261,10 @@ class PlateInitializer:
controlWellTypes = { "H" : self.POSITIVE_CONTROL_TYPE, \ controlWellTypes = { "H" : self.POSITIVE_CONTROL_TYPE, \
"L" : self.NEGATIVE_CONTROL_TYPE}; "L" : self.NEGATIVE_CONTROL_TYPE};
for wellCode in library: for wellCode in library:
if not library[wellCode]:
continue
libraryValue = library[wellCode].upper() libraryValue = library[wellCode].upper()
prefixedWellCode = self.plateCode + ":" + wellCode prefixedWellCode = self.plateCode + ":" + wellCode
...@@ -255,9 +279,10 @@ class PlateInitializer: ...@@ -255,9 +279,10 @@ class PlateInitializer:
try: try:
float(concentration) float(concentration)
except ValueError: except ValueError:
raise RuntimeError("The specified value for well %(wellCode)s in the property " raise RuntimeError("The specified value for well %s in the property "
" %(LIBRARY_TEMPLATE_PROPNAME)s of experiment %(experimentId)s is invalid. " " %s of experiment %s is invalid. Allowed values are 'H', 'L'"
"Allowed values are 'H', 'L' or number, but %(libraryValue)s' was found." % vars()) " or number, but '%s' was found." % \
(wellCode, self.LIBRARY_TEMPLATE_PROPNAME, self.experimentId, libraryValue))
well = self.transaction.createNewSample(prefixedWellCode, self.COMPOUND_WELL_TYPE) well = self.transaction.createNewSample(prefixedWellCode, self.COMPOUND_WELL_TYPE)
well.setContainer(self.plate) well.setContainer(self.plate)
......
...@@ -80,7 +80,7 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest ...@@ -80,7 +80,7 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest
private static final String[] EXPERIMENT_RECIPIENTS = new String[] private static final String[] EXPERIMENT_RECIPIENTS = new String[]
{ "admin@sanofi.com", "mickey@mouse.org" }; { "admin@sanofi.com", "mickey@mouse.org" };
private static final String MATERIAL_TYPE = "COMPOUND_BATCH"; private static final String MATERIAL_TYPE = "COMPOUND";
private static final String POSITIVE_CONTROL_TYPE = "POSITIVE_CONTROL"; private static final String POSITIVE_CONTROL_TYPE = "POSITIVE_CONTROL";
...@@ -88,9 +88,9 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest ...@@ -88,9 +88,9 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest
private static final String COMPOUND_WELL_TYPE = "COMPOUND_WELL"; private static final String COMPOUND_WELL_TYPE = "COMPOUND_WELL";
private static final String COMPOUND_WELL_CONCENTRATION_PROPNAME = "CONCENTRATION"; private static final String COMPOUND_WELL_CONCENTRATION_PROPNAME = "CONCENTRATION_M";
private static final String COMPOUND_WELL_MATERIAL_PROPNAME = "COMPOUND_BATCH"; private static final String COMPOUND_WELL_MATERIAL_PROPNAME = "COMPOUND";
private static final String DATASET_DIR_NAME = "batchNr_plateCode.variant_2011.06.28"; private static final String DATASET_DIR_NAME = "batchNr_plateCode.variant_2011.06.28";
...@@ -116,16 +116,15 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest ...@@ -116,16 +116,15 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest
createHandler(properties, false, true); createHandler(properties, false, true);
createData(); createData();
final String libraryTemplate = "1.45\t20.701\tH\n0.12\t0.002\tL"; final String libraryTemplate = "1.45\t\tH\n0.12\t0.002\tL";
final Sample plate = createPlate(libraryTemplate, "6_WELLS_2X3"); final Sample plate = createPlate(libraryTemplate, "6_WELLS_2X3");
setUpPlateSearchExpectations(plate); setUpPlateSearchExpectations(plate);
setUpLibraryTemplateExpectations(plate); setUpLibraryTemplateExpectations(plate);
final MockDataSet<Map<String, Object>> queryResult = new MockDataSet<Map<String, Object>>(); final MockDataSet<Map<String, Object>> queryResult = new MockDataSet<Map<String, Object>>();
queryResult.add(createQueryResult("A0"));
queryResult.add(createQueryResult("A1")); queryResult.add(createQueryResult("A1"));
queryResult.add(createQueryResult("B0"));
queryResult.add(createQueryResult("B1")); queryResult.add(createQueryResult("B1"));
queryResult.add(createQueryResult("B2"));
final RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails> atomicatOperationDetails = final RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails> atomicatOperationDetails =
new RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails>(); new RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails>();
...@@ -143,7 +142,7 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest ...@@ -143,7 +142,7 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest
one(openBisService).listMaterials(with(materialCriteria), with(equal(true))); one(openBisService).listMaterials(with(materialCriteria), with(equal(true)));
will(returnValue(Collections.emptyList())); will(returnValue(Collections.emptyList()));
exactly(6).of(openBisService).createPermId(); exactly(5).of(openBisService).createPermId();
will(returnValue("well-permId")); will(returnValue("well-permId"));
one(openBisService).createDataSetCode(); one(openBisService).createDataSetCode();
...@@ -178,14 +177,13 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest ...@@ -178,14 +177,13 @@ public class SanofiDropboxJythonTest extends AbstractJythonDataSetHandlerTest
List<NewSample> registeredSamples = List<NewSample> registeredSamples =
atomicatOperationDetails.recordedObject().getSampleRegistrations(); atomicatOperationDetails.recordedObject().getSampleRegistrations();
assertEquals(6, registeredSamples.size()); assertEquals(5, registeredSamples.size());
assertAllSamplesHaveContainer(registeredSamples, plate.getIdentifier()); assertAllSamplesHaveContainer(registeredSamples, plate.getIdentifier());
assertCompoundWell(registeredSamples, "A0", "1.45"); assertCompoundWell(registeredSamples, "A1", "1.45");
assertCompoundWell(registeredSamples, "A1", "20.701"); assertPositiveControl(registeredSamples, "A3");
assertPositiveControl(registeredSamples, "A2"); assertCompoundWell(registeredSamples, "B1", "0.12");
assertCompoundWell(registeredSamples, "B0", "0.12"); assertCompoundWell(registeredSamples, "B2", "0.002");
assertCompoundWell(registeredSamples, "B1", "0.002"); assertNegativeControl(registeredSamples, "B3");
assertNegativeControl(registeredSamples, "B2");
List<? extends NewExternalData> dataSetsRegistered = List<? extends NewExternalData> dataSetsRegistered =
atomicatOperationDetails.recordedObject().getDataSetRegistrations(); atomicatOperationDetails.recordedObject().getDataSetRegistrations();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment