From 261aabff0d90ef25a0686ffc647a923b20a48fc8 Mon Sep 17 00:00:00 2001 From: cramakri <cramakri> Date: Fri, 18 Nov 2011 11:59:45 +0000 Subject: [PATCH] LMS-2631 Added new metabolomics format SVN: 23714 --- .../etc/metabolomics2/data-set-handler.py | 82 ++++++++++++++++ .../etc/metabolomics2/data-set-validator.py | 91 ++++++++++++++++++ .../dist/etc/shared/shared-classes.py | 39 +++++--- .../examples/Metabolomics2-BadData.xlsx | Bin 0 -> 11000 bytes .../examples/Metabolomics2-Example.xlsx | Bin 0 -> 11050 bytes .../examples/Metabolomics2-Template.xlsx | Bin 0 -> 10499 bytes .../examples/~$Metabolomics2-Example.xlsx | Bin 0 -> 171 bytes .../MetabolomicsDataSetRegistrator2Test.java | 80 +++++++++++++++ .../MetabolomicsValidator2Test.java | 66 +++++++++++++ 9 files changed, 347 insertions(+), 11 deletions(-) create mode 100644 eu_basynthec/dist/etc/metabolomics2/data-set-handler.py create mode 100644 eu_basynthec/dist/etc/metabolomics2/data-set-validator.py create mode 100644 eu_basynthec/sourceTest/examples/Metabolomics2-BadData.xlsx create mode 100644 eu_basynthec/sourceTest/examples/Metabolomics2-Example.xlsx create mode 100644 eu_basynthec/sourceTest/examples/Metabolomics2-Template.xlsx create mode 100644 eu_basynthec/sourceTest/examples/~$Metabolomics2-Example.xlsx create mode 100644 eu_basynthec/sourceTest/java/eu/basynthec/cisd/dss/metabolomics/MetabolomicsDataSetRegistrator2Test.java create mode 100644 eu_basynthec/sourceTest/java/eu/basynthec/cisd/dss/metabolomics/MetabolomicsValidator2Test.java diff --git a/eu_basynthec/dist/etc/metabolomics2/data-set-handler.py b/eu_basynthec/dist/etc/metabolomics2/data-set-handler.py new file mode 100644 index 00000000000..eee034223fc --- /dev/null +++ b/eu_basynthec/dist/etc/metabolomics2/data-set-handler.py @@ -0,0 +1,82 @@ +from datetime import datetime +from eu.basynthec.cisd.dss import TimeSeriesDataExcel + +def set_data_type(data_set): + data_set.setPropertyValue("DATA_TYPE", "METABOLITE_INTENSITIES") + +def retrieve_experiment(tr, exp_id): + """Get the specified experiment form the server. Return the experiment.""" + if exp_id is None: + exp = None + else: + exp = tr.getExperiment(exp_id) + return exp + +def assign_properties(dataset, metadata): + """Assign properties to the data set from information in the data.""" + propertyNameMap = { + "STRAIN":"STRAIN_NAMES", + "TIMEPOINT TYPE": "TIMEPOINT_TYPE", + "CELL LOCATION": "CELL_LOCATION", + "VALUE TYPE": "VALUE_TYPE", + "VALUE UNIT": "VALUE_UNIT", + "SCALE": "SCALE" + } + + for prop in metadata.keySet(): + key = propertyNameMap.get(prop) + if key is not None: + value = metadata.get(prop) + dataset.setPropertyValue(key, value.upper()) + +def convert_data_to_tsv(tr, dataset, location): + """Create a tsv file containing the data and add it to the data set.""" + tr.createNewDirectory(dataset, location) + tsvFileName = tr.createNewFile(dataset, location, incoming.getName() + ".tsv") + tsv = open(tsvFileName, 'w') + for line in timeSeriesData.getRawDataLines(): + for i in range(0, len(line) - 1): + tsv.write(line[i]) + tsv.write("\t") + tsv.write(line[len(line) - 1]) + tsv.write("\n") + tsv.close() + +def store_original_data(tr, dataset, location): + """Put the original data into the data set.""" + tr.createNewDirectory(dataset, location) + tr.moveFile(incoming.getAbsolutePath(), dataset, location + "/" + incoming.getName()) + + +tr = service.transaction(incoming) +timeSeriesData = TimeSeriesDataExcel.createTimeSeriesDataExcel(incoming.getAbsolutePath()) + +# create the data set and assign the metadata from the file +dataset = tr.createNewDataSet("METABOLITE_INTENSITIES") +metadata = timeSeriesData.getMetadataMap() +assign_properties(dataset, metadata) + +# Store the original and tsv data in data sets +original_dataset = tr.createNewDataSet("EXCEL_ORIGINAL") +set_data_type(original_dataset) +store_original_data(tr, original_dataset, "xls") + +tsv_dataset = tr.createNewDataSet("TSV_EXPORT") +set_data_type(tsv_dataset) +convert_data_to_tsv(tr, tsv_dataset, "tsv") + +# Make the original contain these +contained_codes = [original_dataset.getDataSetCode(), tsv_dataset.getDataSetCode()] +dataset.setContainedDataSetCodes(contained_codes) + + +# If no experiment has been set, then get the experiment from the excel file +if dataset.getExperiment() is None: + exp_id = metadata.get("EXPERIMENT") + exp = retrieve_experiment(tr, exp_id) + if exp is not None: + dataset.setExperiment(exp) + original_dataset.setExperiment(exp) + tsv_dataset.setExperiment(exp) + + diff --git a/eu_basynthec/dist/etc/metabolomics2/data-set-validator.py b/eu_basynthec/dist/etc/metabolomics2/data-set-validator.py new file mode 100644 index 00000000000..ca28902b986 --- /dev/null +++ b/eu_basynthec/dist/etc/metabolomics2/data-set-validator.py @@ -0,0 +1,91 @@ +# validate the header -- row 1 contains a strainid, row 2 a value type, row 3, a value unit +def validate_header_line(row, first_data_col, line, errors): + # validate the strain + if row is 0: + for i in range(first_data_col, len(line)): + strain = line[i] + if not isStrainIdValid(strain): + errors.append(createFileValidationError("Strain in col " + str(i + 1) + " " + strainValidationErrorMessageFragment(strain))) + + # validate the value type + elif row is 1: + for i in range(first_data_col, len(line)): + isControlledVocabularyPropertyValid(line[i], + "value type", ['VALUE', 'MEAN', 'MEDIAN', 'STD', 'VAR', 'ERROR', 'IQR'], + "'Value', 'Mean', 'Median', 'Std', 'Var', 'Error', 'Iqr'", + errors) + + # validate the value unit + else: + for i in range(first_data_col, len(line)): + isControlledVocabularyPropertyValid(line[i], + "value unit", ['MM', 'UM', 'RATIOT1', 'RATIOCS'], "'mM', 'uM', 'RatioT1', 'RatioCs'", + errors) + + +def validate_data(time_series_data, first_data_row, first_data_col, errors): + chebiRegex = re.compile("^CHEBI:[0-9]+") + bsbmeRegex = re.compile("^BSBME:[0-9]+") + dataLines = time_series_data.getRawDataLines() + lineCount = 0 + for line in dataLines: + # Dispatch to another function to validate the header + if lineCount < first_data_row: + validate_header_line(lineCount, first_data_col, line, errors) + lineCount = lineCount + 1 + continue + + # The header needs to be CompoundID + if lineCount is first_data_row: + if line[0] != "CompoundID": + errors.append(createFileValidationError("The first data column must be 'CompoundID'")) + break + lineCount = lineCount + 1 + continue + + # The compound id should be one of these forms + compoundId = line[0] + if not chebiRegex.match(compoundId): + if not bsbmeRegex.match(compoundId): + errors.append(createFileValidationError("Line " + str(lineCount + 1) + ", column 1 must be of the format 'CHEBI:#' or 'BSBME:#' (instead of " + compoundId + ").")) + lineCount = lineCount + 1 + +def validate_metadata(time_series_data, errors): + metadata = time_series_data.getMetadataMap() + validationHelper = ValidationHelper(metadata, errors) + + # validate the header format + validationHelper.validateExplicitHeaderFormat("METABOL HYBRID") + + # validate the timepoint type + validationHelper.validateControlledVocabularyProperty("TIMEPOINT TYPE", + "time point type", ['EX', 'IN', 'SI'], "'EX', 'IN', 'SI'") + + # validate the cell location + validationHelper.validateControlledVocabularyProperty("CELL LOCATION", + "cell location", ['CE', 'ES', 'ME', 'CY', 'NC'], "'CE', 'ES', 'ME', 'CY', 'NC'") + + # validate the scale + validationHelper.validateControlledVocabularyProperty("SCALE", "scale", + ['LIN', 'LOG2', 'LOG10', 'LN'], "'lin', 'log2', 'log10', 'ln'") + + # validate the data position specification + validationHelper.validateStartDataRowCol() + + +def validate_data_set_file(file): + errors = [] + time_series_data = create_time_series_excel(file.getAbsolutePath()) + if time_series_data is None: + errors.append(createFileValidationError(file.getName() + " is not an Excel file.")) + return errors + + # validate the metadata + validate_metadata(time_series_data, errors) + + data_start = getInitialDataRowAndCol(time_series_data.getMetadataMap()) + + # validate the data + validate_data(time_series_data, data_start[0], data_start[1], errors) + + return errors diff --git a/eu_basynthec/dist/etc/shared/shared-classes.py b/eu_basynthec/dist/etc/shared/shared-classes.py index 5ff2e494996..85911070ab2 100644 --- a/eu_basynthec/dist/etc/shared/shared-classes.py +++ b/eu_basynthec/dist/etc/shared/shared-classes.py @@ -61,7 +61,8 @@ class TimeSeriesDataExcel: value = line[1]; if "BLANK" == value: value = None - metadataMap[line[0].upper()] = value + if line[0] is not None: + metadataMap[line[0].upper()] = value return metadataMap def create_time_series_excel(fileName): @@ -123,14 +124,8 @@ class ValidationHelper: def validateControlledVocabularyProperty(self, property, displayName, allowedValues, allowedValuesDisplay): """Validate that the property is specified and in the list of allowed values""" - if not self.checkIsSpecified(property, displayName): - return - value = self.metadataMap.get(property).upper() - if value not in allowedValues: - if len(allowedValues) > 1: - self.errors.append(createFileValidationError("The " + displayName + " must be one of " + allowedValuesDisplay + " (not " + value + ").")) - else: - self.errors.append(createFileValidationError("The " + displayName + " must be " + allowedValuesDisplay + " (not " + value + ").")) + value = self.metadataMap.get(property) + isControlledVocabularyPropertyValid(value, displayName, allowedValues, allowedValuesDisplay, self.errors) def validateStartDataRowCol(self): if self.checkIsSpecified("START DATA ROW", "Start Data Row"): @@ -147,6 +142,7 @@ class ValidationHelper: strainIdRegex = re.compile("^JJS-MGP[0-9]{1,3}|^JJS-DIN[0-9]{1,3}|^MS|CHASSIS\s*[1-3]|WT 168 TRP\+") def isStrainIdValid(strainId): """Return true if the strain id passes validation (has the form sepecified in the regex)""" + strainId = strainId.strip().upper() match = strainIdRegex.match(strainId) if match is None: return False @@ -155,6 +151,21 @@ def isStrainIdValid(strainId): def strainValidationErrorMessageFragment(strain): """Return a sentence fragment describing the strain validation error.""" return "must be either JJS-MGP[0-999], JJS-DIN[0-999], MS, CHASSIS [1-3], or WT 168 TRP+ (instead of " + strain + ")." + +def isControlledVocabularyPropertyValid(value, displayName, allowedValues, allowedValuesDisplay, errors): + """Validate that the property is specified and in the list of allowed values""" + if value is None: + errors.append(ValidationError.createFileValidationError("A " + displayName + " must be specified.")) + return False + value = value.upper() + if value not in allowedValues: + if len(allowedValues) > 1: + errors.append(createFileValidationError("The " + displayName + " must be one of " + allowedValuesDisplay + " (not " + value + ").")) + return False + else: + errors.append(createFileValidationError("The " + displayName + " must be " + allowedValuesDisplay + " (not " + value + ").")) + return False + return True def getInitialDataRowAndCol(metadata): """Extract the initial row and column as specified in the metadata. Returns an array with [row, col].""" @@ -166,12 +177,18 @@ def getInitialDataRowAndCol(metadata): if first_data_row is None: first_data_row = 0 else: - first_data_row = int(float(first_data_row)) - 1 + try: + first_data_row = int(float(first_data_row)) - 1 + except: + first_data_row = 0 # convert the column spreadsheet value to an int if first_data_col is None: first_data_col = 0 else: # columns start at A - first_data_col = ord(first_data_col) - ord('A') + try: + first_data_col = ord(first_data_col) - ord('A') + except: + first_data_cal = 0 return [first_data_row, first_data_col] diff --git a/eu_basynthec/sourceTest/examples/Metabolomics2-BadData.xlsx b/eu_basynthec/sourceTest/examples/Metabolomics2-BadData.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..59033160ac866fc6f6e0a7dec0af4041462a9a34 GIT binary patch literal 11000 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 literal 0 HcmV?d00001 diff --git a/eu_basynthec/sourceTest/examples/Metabolomics2-Example.xlsx b/eu_basynthec/sourceTest/examples/Metabolomics2-Example.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c088af65b2b61a70398ce1071dba9c3254fa3bd0 GIT binary patch literal 11050 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 literal 0 HcmV?d00001 diff --git a/eu_basynthec/sourceTest/examples/Metabolomics2-Template.xlsx b/eu_basynthec/sourceTest/examples/Metabolomics2-Template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..bfe543475cb730817d5da050ea6235897d4c5de9 GIT binary patch literal 10499 zcmeHN1y>x|wr<>Af=louH~|8|-Q8V7pmBG13p6gl3GR(M1a}FR;1=9nUT5yRYi4ri z{epLEt**0bRqb8fr@y_wZHh85u($wt03rYYpahUTeU&nV0ssi$000~SBD9W(t&NkJ zjgx_@yPcV%9+R6jkRlfrnm!u<4SD{*$N%FU=v5t+hi1iWPrpG=*B`a<4`dAq4iu1} z!6MJL`LGaTv*ZLH)Zkj5%^LCsTdEaUYu%BRdXawWG`$E!!-{q-Ai#%-^Dk}Xv{8zf zyEXBlVx!)wt63IesP{AGX=)`HZ-8Pksq0bZ5M5K3E+ewQ!{_(g04?^bV?Fl;qn2ow zzzs|q+A+R9MkLvqu@4)(A+rS6B=7;<Ja>ZDUbZa#*w2^F5w0p!?iDw4eTA|9Qu6?+ zBJ*jDX@&PSLFzy?D^%qb^7!{O3l39uyq{9w0}-1tuWS3;?Z=wk26w^HIdHMyz2&R} z0x~LALLa=JwoX3SBGJBMLLphH(9F%8O3yp|MwC3y_e|*FNU-pDMJLW81~;Y-?DwI< zMZ!b2NeSx$MNEEo0nKaY=)CLL72jJ>-XUnZ<%F;aJrjX8KoZ_V<ho$MWYwvQyg1Ni z%whte&MeIegaN_S^D_)U@o$Ey=q2BE1-T;&u{#uqVH!A?0Ueo{ex3hokpGXZ@Gn0- zDt=rVh7~jPIN%s_dwH}zAdF)v60t3O27v&yAaGzqOFiA}?HQQeSoMtzG~#tW8Vhut z<}SkdI#bP6#U!n`$=EW+1;30wUW%Y7HNi_V5AtWHnOAGzTGAj=bWpKu`J`HSW15YJ z6st|QG!<67D#+h4Ln4vj6%~zc;R%$q9XiwRUqLN0mj%1RuP>Jik&aO+JY|hK|IqR< z_9Ph`?ndOR959VS3-|vxK~8e-y4^m|ot>=5IoI;g_JvGpA}70^<RhN3JcD$y<Kv_~ z(BRDZuB4IL$+d05>$1Sk0{blHyBQ7Y+LGk>li(%NKbZ;6&0*CoWKSeu001HYB9t4D z`CpdeYU^NSY-?-vi^2YFHBb;5gK*vd@1r$-)Ut;KGw3+DJ#gNWap^H9XrL)UxWf7l zAgr%LTTflLMBd>oCai)G;K|B2_9pFie%9ms?Zr9_mGd$KeGLgL&&K{37<t)coGX?h z3|#7bO!|r-&QL|qpxmHpE`u!Y5IQ_zUDDqS{WZg&CJBcbf3^&$uV2V9zB*ATz0F1` z$^D69g9E0dR<^nvuh-fe#h5E(=E1ezHf?Mb#B~hA)2>MQ&fW-lrdmwh?vq6A05<)= zFsiEz8)mGx_Bzsf(azrSi}D5@<HsRZJvV7q@Qz^wjS;{1caYfTigU)B_|U-vqaoiA z247C9@pj)!w0{ClNUm1jE(8o55a9gsz!2d46*5uEa<S7am~B+2<Zo7{^T+y`)Z*2C zh86`)Aa@-tI2T6G&c^^lO@nWaWwD3UJN-e2gyZS%w)#&jMIl}=`}vb_dQ2~+1yNL_ zyqR|AnD19VWA8LoxS4R^Ucixf)33A-dYUjxm@vUY)xEYj^lm{Gp|e!{&M1pQ#7<{| zcYRa0GXchT+p+{yrhO7q!hgl|HWN$z%9my2Cp8=}dKcG1AW+kyvHw($QAc9<ftuJY zjSy?OKC7|2DKsQLgtwzKKeQy9fnN@z(mx1$34F}EV3@=RqAxJIP2b9+!Mm>VdO=f! zEv=mXl+A2a9-Wo;0yl9ZlZ!a-(-+5B<r{Qn6KH?&;?L9<M|h52@oQRpLl-Ky!=r6k z-QzW9Z(~5_Sl#2*7!>2+euf(Qp6s3e@eNo>q-Vn~Cxx@rob?&<xpXvrqa+0=xNb2S zH<Iug4uXr4BNf#82RYg?n$IQoc_BY$s*0b%#jDYRKl)6dWAmt+^F#?4d93WciANsd z5#XOEZ`t}mPU`p<_j*I?dd<-=Nk<!onMb*XsbAj=#Pi93&`hL;e01CLLOMqB@~iq% zK?aC<-3wg1Tv*){hBYgXzz#Nz9!qO6@A-J|p7F-&RD`hrOMN<&$`EE>2(A7n>6*Yc zrf9(e0IM$n00?S+fx^+r9cbqG%ZnUnE5+t<V)|6hJo~w=(0l^A)COcMmM9(Pd;!^1 zHftcr8kbj7v3L$X-uZB1){Mq~>im4yDH9OAbAEF^!p$D@Y?N-dA6!TXdRg^jDb896 zYbY#S&Cu6d`}_NO^}?_)#N+_@s~GdE(A&z6o76@7J2ScB8USTYr~YfOyHmy+-RU6H z1_u$i<z6<qFkyDRcMG%y)I)WO-K4f0X*@_q-AtHdpei&;;i(-jN1P#35nLU%v6(T$ z1$AtGA6=x>c$&}>9arIQ<Ry-nRUG_6Hc)jlTn5!fO7Ml|a4Nf_AIG%`gQ|Hj+Y4k} z|5t%`H*Ypwt0#^pbkNi97clmN?byds?*pjoES^QC!w`-0rYHU2fP7Cv9Ule0XVwvq z`!#C}4g|#y<bV)ggkb=dwYldk@_#xbU&%oj!w=X@x4MfT~MA9kU-U5SKQ9Pjt@x zalEVX(D3TPbEl7Zc)*Y->b&i%T%C1}$x+W4p4?Yxv{EmhMe8aGD7x8sdDf$mT{UT! z3fDP(3Q&facH}I1pPMw%s6&$3%5rvL-%tjO-qPMIcXUCDOI!NFA<*TSg>)sBcH`9P zj-~njeA}1?RbthRVHy#t>TI94ta3N)KBEsASO^4vTamUoX-bf$)E;>Zi%Y}}+L$b+ zF0o|{?+hm(oVSc7(9j|qOq?+iM)@hEkq5KN*fu7wUGz-0n3YNNpeMMp4|fI7x52J| zpP%77nSRc=e9Ze`cw}oLvpM)ui5v?HYt`AWf@}@AWl}vT2BXc1^h4yynlci|>2=MZ zki?;v0y8yY?g3VrD_@DW|8}^-trH$($?WGLzUuf24=wRsr`&t1DFlhzXXz||@`E)) z0ga_|LxI3Yr|{6gN7O6!`SJV5Wr7E*lgh3R_~#Pr#Ooo~j2@>7$s_bLp6jQQ*0IID z4><2D-{q9#N8-x8KyaQisFw}V0GFVSC%~pDH`w>c0^Yq<p#$ozym{wlg;!oxX<CGL zmG2MYzi7AW?DLSfSH8Iu<MrH<Ehk9RZ-`Kz&s<;z?yY)F6gVm;a+QH)7cd&5nR51d zQW;XLH?}QhK#|$cGf7}=AWocjiZ*DuyxJE(ZvJ#k)L2Ok33*>XZCzbU^&Z28kV+vz zBCTp{*F89P%(5H{Apg<(<(PrZ&u!fvDHp{`FTL{bS)NJl-G~Rlo4P(<;x1n>!6=XQ zI)cr#4>Rl&#@{Y!j;D!X&2srHRxWP%E$Q2>Dz>d==P#hdw2$l~6fqatSI&XNz3mUL z#Omi>Ea)4UdM3wtZ|ZZOVw54g&vdG!vL{8hI&Re@5uj`iqmny*8Dlsl_Wf`mb1Ck9 z1C^&Fb8~qIm9M_Ulii_j_*2$}HC|;*;#>@niG9x$bw|Cf{CI9er{Fow$Y%M9j*#Ug z5h$bd%j0loMb>j6)-X<$YRuh;em)zfzn;L0ya?hCj)#^{X>89g{>cY1kRtFaKuGBb z0g{#fNlcCwW@b)~%zrFwzuZxV+LFx@H>S5i_A|xqk7ltK!&SP}=n;$)#({Fo;~ZjI zqSQ(>Kj&?#pW8zdOkYTG?q78gNpHV%H0RFHYUitqJ|D<m&wc%U0!25}Sv8?`3IAwE z;n>`9PASca=A&po^7TN%z02ix?3Vrjf*N}vDT`ByomKgL@bPQy+9Y~~i?SYp#7~Tq zZizYum+^5^0gHXH0Th=y-Mp@bngcT2qH6X-HgG?{Wz#U>rf8EBm6pq;;pGL%6JSyP zgF8YzYm5jq+eUtE<++bP*B|R~;(<iH-iRi`bT;>AQSDo*$TY7G{m00I_+#H)JCe(m znhj$4OSMpGsWr~6t<$<Z&Q5LbpnUMWoL*%8xr}&f_~d4QZv%k;N+d3~itg`jYW0mH zxCI@DWPwY@@>}+WLWV#k-IME8*in8hWkk8yd17+2IAb=hw0fLg-ZTEa0O86vB7@3L zu%JjW_g1rrb<8LN?wnjGs?YMnatxG#n}&xz)FW-~@x4Fa2MRW;XxD*Cu>>gcu#k8u zahOp8ABF&l{AuTi8yfGjr#wP4xwrK>6uPOS^{>(OBZElel<WwxTk#<eV|BmwFQfvv zK=&p$4T)19ylbUKspx(VM{iiL49fItaz$bx_pbt}Z(b#?%HC>fn6nBQGsnaOpU7W9 zLN#FZGPaz$48s-rBDAH{WiLmnoqqyRWCq$;=pNV;=v~-IFym)~YB?W{t#<R!7%^4w z9L6hn3UfW^Px<JK@PXk2!oo26r_vQWLq!Ful#T<y*4<23@z^*6k&2_WOCSNS{LpxJ z=s{c6R`GsLIV#=k905j}N?n|^(_$U{rUAL<_gVQeF|IKJ$7#<RGxG57XY%jRN+~E$ zMrM;lA_?{Db{W5lTW}z^l(F&=$a9`lHDL=YFjMXDO}8xnlp5dUdq(f4SEqcZoj{5a zyo6Frv$p7L>Gh1BncsBizSgHiw(}8xi(45{jAZ=T565MKJfZ&Eg4C){zCEVsf*N;= zylsG%F_}^tT<x34?sOpO=10s2_ULH*!;`@TFMIR4pt}RX)XcbZBk_u)LnHg^wa9a& zgfLXsy~>y$lyNSPmt+Bl*suJ9#n0=EAE)#6A5s3v2nRgB6+gfO01>3W%3^;60!|iY z)@ICqoLT<}2ejmDiNy%oArYdur>zN{JduQR$$T}j#k6>}&di1z-<3RjOKln<-6<Ma zf|^=XNcU5ty`W%$`ns}@TsC6FOh+d#d&_>N+jnkCKfmn>j}KYb_g3atchMUuIU+Bq zx1^|w^vhwxs42-OOlJ^}E_pP*!BFGL!>61EaRea6bw!W5t~AAPsfrp0`0>XPH)4rO z7ZA(HumzdDsXR-dKCu}Pi^6*!F*zl;O0`N{Td*Z<X3fyYfutB<V(970olhymH_A3Y zlG;G{o>qD<_)~a=xf}^{ASsFJTVZ+ANF=8)Eh@k}7@rxc{#SyiGH}d9LSG-?WYXu7 zPsGK0XGj*Y_4*&ooCv#C4HpJ*^L!}l7K>*qtzSH#`4wyFw*0UGm%<6abQ&QhY3mKW zx5~V<WZ%((UdXC#)k&O{9{rkpQ#rD$Ys;BldMW#2c*gHwd=b^Btww!G+vNn_^t6=y zM%%G;R@?E{g%$hF82C<m^eeGquZ06k;5Vp4C$=Lv(}9JU7wzaLm(uWAxfH|^2U9OY z-YcCuF!o_I?E(a02-P`+EaT%T(J3Q!xQ|dGz<^dEyPwf|$Xg@vNx`P{79~Vo_Y5Hs zDQBLK>q~RYpK~Ce&+k2a&UQmV{jmyU-nQ=Vf_S+J6OjzO9|w;Oe8PM@uVzc>vTjdn zqMmPCVtwvTRRl0!S(Ho;k7qrdJ^UPI=6||Orz5*b>U?Btl`wfZN$L=E<&IiU*x#52 zYUd^wWA2{G>BKs@s<J5^fLcy9-0pcBzTbKeofeAW=J+r%2__D&&Ltac$eo8eau`d~ zbtAQt8Ghy7$R#iCvu3Q@cWC0Z3;NL=j<a~h9bA!0SFmxfE=uzDnm`_xEG~#Xf8`WL z`29D&?3vSjCN#KYuc8T<h_n<By{SBJy0}77UXGAPSuakJBGQ$EWeK@4FLhgx$O|Mm z|5S-vGNTw`+x6=1>R2<3{<4FUB~3AYnid?aBzx;(iYcmYZcB`?1pc%Z=mSQ$NBj_< zEwp>4^j;=qdXLo&cVb6<ahvl%^`MQJ(8DR}S0*bUgipByhxS{6#|{m`7wo-IbdEjV zS=e;nKX3(jI&Btl$YDO3zj1n#qs05jRXCWQ#+o+~ZH?Y)-4|_$A`Ysgc993Kx;Oe7 zZT#rlFpU+g7)Sry;C*eqg7$Ro?W)hnylDLe4d0`3`Te|i^#V=5BiEqFkfw$lK@;OB zzgBk@fs>)qbSlhC26VZPumZK)N2}t{#6;AMcYY;B#A~=$^Rt5Ngo9C+lDP>o+)Jru z%(l^?-pw_1J!;<ORgZ$k;9&$8cQNK2iNJtp!go}TPa|;U7VweCI!#HeaJ9@Y%SsZp zHMM7p%(XMA%2^1Fxvhxa;4cU1AqKRexVfXn>}qpl$gxnt9J=!QomZvMKfI+JDyt6> zbrS@JWo*TBmD0MnBd790OEM_zj_r(gTdmgBCbE2F74XG(au_q*Gu3nXQW8$HwP=jQ zV+ngXyEO|4=C+0v;ZE!x=MK)6YP0PD!fNp5U~^iHmx-z5t3>WUm6ddh^<)It4{_ru zTbmFr5Tt2n6=~+uXgwxtSn(_{^#jt2UQ8I9kt%PJPeThIh9seeQmbwmCac#SADDbY zy4A#*jE0ve8t*eE7rE*BviKP)(XPo5SzDk}F6FA;ee3F5*>u8j7V21qNs>7Ce$pK+ zO(i!9*QNTd;b-YRe{208(e^uBVj2%-smk&jR^B%L39&9bR5yT!^nCFiWDR)xh# zniYvAtEdc*(wCtYpc{%$h%zwdy0(3V&@Z3sx8Go>e6zDqxpxYJ4YtpHDKtP<M+5Ty zz*1_S*I#2wNCi@&aW=D@Jpzezdo&|d{3IjEMpXXc1S&%#`2O?3F{>7NFZP10K-X3t zgF*aDxqpY}hH)fe6c0Fg;x_%hLvfP*@l6}$_y^Mk%tzy9nUXEFHPj9dJ{)HuJbc2= z0xc`vZ&6=|OPd@pziLGqRnL#-+kFVU5MX&OLQH+E&qlC}Jr=PQJ1OqG!w^z8nAAgK zljM@TFU7bgYq0=H)z(yuy6`Vr-Bz`4Mq5%|C)9$?BYW>N#+W#jD!9MkGfyw1hLRdA zftxBq20k+>X%cPkVB!#*E0sL_2)ia1&Td!>@fkTtrcUh!6$d&gq#W#>cTwLD=94yZ z?q3j!Q)$&GgoL5ToS#dqA?XNTS&6rcaaza~;*?Y9o{|#jcB58G9oD@GOCG0XqK`7Q zSb(c;qCIEzv(?ht_$I;IxkPJK{_Sg`X9SIJpBW1Mv1{t}W^K{%fzWBRf3x54%xSt_ zk~?w+SGwEDTV+G;G$*;|;2ab7ANdE{<Pa+S&#d`!DV&xTk~MoE|DO@-AB-8Lu2-23 ziC8P^o}o@ZpV-4doK-WdTKP<ghNtV&hkkqP*M3?{O;Xy2zAM#o01$BY1!~V}Dm#09 z|L}EkiPJLTi-g%!Vp;Dw%D3h^+Q;nI#~u8#+Z9yQB@IQUZwJ4>#yYy6B|lF3&=<Qd z80O@cgP-d8sYc7~b0>l_C94@)@!ELIDYDefrl$f&Mt1pU)kOW>`)UnJ?UoRuF5l3= zLl<07z?zDf<wr?whB(;AbwOf#lhTvp3AHeCg;Chr5~v6?#^P2><+<XM_33tV5^L$O zd+ZU+cKiKU-n$6nG1#R+h6#7^UGI_NWRK1|Z5syB?5QKWn&Iy|hDxyQ`{hYILM!y| zBD-3sCbtt4U}b88d75H|o<pkhpnaf07zx5KxHR4I?Qw4zhDSz4=+^`mrO24hn$Fgo z<wK6SLdl&b^&4x20?M>*Gi|n@TD#Zh<4JiE&lFsqBzK=Ex{zOs(wSDb;fos5M=Ha} zv%L1l`YbOtyB?5{8;P}o-8W5tniasJ9C=W3hDzau9k0ff#Tb|4C&>X9^+5zHWZE5f zblrW*al~ivbjG1`-l6wrChE;C3gN2Yu-_>yRZ7S?eV8%c(4*{lzA#;zAa;3DMkcA| z31)@Gr$zoQ=y_Fs5jCkYAO6ygRN@x&6gbTl^{y$;z=$>cIAT#Y!5~g!YfQzwn2kYk zTzIU`38C)gSOjU_CQF)22V1s8wa}?i1?v|caOO7oR>d!M8dMC0oE-y}zr?g#uqsBN z<6KQ@H3QBClWP{6A?+A=)(JDz)h0*61r_8#zYn2^_d(jZ*`F~)8A=&n)$?t_vtpW| ziYT@76|f-6sFIh^NFT=EBfo;&Bxo8yGtC|%2q_6@=P3+;Hy+%Z{x}%$_DL|QCdTx# z=^K*+4B-G9yo~zs^Z?tZoU&El8aU#8|2Jl&gG6%^f>S<S#DO$cby5*YoFvvxuN6v& zSCSR9Bm%HKgFA~WDFWXU_9!ZHzj8OCQ2)G5T23S59O9|h#Mz*awtPYA2+N7ks3aMY zGk&1SsD`8RVFK*WsaX5Abjd1Q+BooP6J^~~8|4c%@4V-eYUa)N3yO0}tvm)!Sz(yT zN`yu`Om4de20z!R!6k{|Tj|YWd!iZ4Cuv{5jTvWxFB3f%(Jvi|`)DLoyBAQe$g^=0 z#YEU$@e6A?<hyZ|5rrvZ?#T-gw(a)cAtTg+_M$M2gZFS=f!)2?E0TzPoai?JXV#1P z0_hU3#QjP?3KlMg8R;+%iuvFx$Bu;uW@nv_T=#4;q`dEM5(uB6io)@Yr#AXTXC)Br z{k*b-R~R7vzPXyOwL=xrb2A{ky>fKa+ZtTP6q!7}lEDl_VF+CGEgwWtmF)2K4VK;2 zC?GIR`+~pk+|W1c`;We*0JLa?2&vUELV|JJe+A->7Df(crYcSjA8kJTQJBkD?XpQ1 z#B9^p6NtJxfbS12DfgrA6RkI;i=$L?_};l#23zaoT6Cx*kZUl{{F6YZUM!!a8?JZc z%w;*9YhwjiitY1yzphJA*8mNUenhsyo;2*s#nCVqR1EcY4M!1lwTk@rpe%vgF|3o0 zU1%lDS%LTCX2B)-Eo@-nv9hRg>eDZJo)z`d+ZBotB~!#`p$2Wzmbjl%;TbUVj-iQW zI*9Nxp>vL%c2#ctkVlYn-2nD%esCRm$xs9+*Kx;6yK`_F;yj*pRcw;A8SaSLdZSyp z;izOkk(e*q__m?0CmnK<T)bI)hH8|&0klJA>T|t&*Zxw@1(tbn6lROwpJFWg$6-=_ zG`ym#<#&sFC6kgadsRS?T4HXySu3S8CPwu|j>dlQDZX;c|6Yu3*#V?Qn$Q0xUY0CJ zz@om+5a(Ps>H|`did42ElWb*Ojduy}6|lm-Q@K*&@Z4kG#ddjELq%OptI<lLsr3G( zylp>*V@i8evTaL^g_}_8tIu=S@-)<pU83<p1q)8LjRWF^2j&>lzLWcH1Fx-b^{qIo zCRGL7C7!N#m?zqyTBV9U_39vm&&68hr81-==U5asAJKdm*=WK6dY%Qkgf-NZtfbA# zY*6zFG=qD`e@NoGQUL>O=qZOyTP9tcGv~erM}>~y?DY)P5ysAW-#}>TKUry3;%Z(D zQsCEvpa%=m88WpsQFO4ib7VHLbujytz(Lxm|7{3COe!c|Ng<F0H+V(v0VDrdk%uG= zUNhHRfr%9>@3g$$HA+%uT7BWE4UV&Sq_=<B@yK<&?PLAoFzpSr$-eqlm?$f<;Hmmd z$<U-@6S}RUA*o8h+wuSs(#~8pd-phdId`ko$vUE_(k}SV`ERy(BzSi?zRsVKN}5w0 zE9!r*7iZhaD(p@>#ZZUR@3oJh;igS7X+#L|c$rJ3e1cRgAjb}X?Vs?2-Ficd)g_>h zAigL-3~#ob0Oqymm}Wi7V7#H1KWZzdGnsQ%N=9Y%@(D2D!cgcbF)F{)u@@Ah<=%o% zv67?gcD17Hsa5uE57BBkO<w*+VS@qM*F7zxyhDV=x?ypO@=?~0Z@G7fju4ZTBw+3d zN-&kGG;Wq$x$Ek<ySFnDBI|#axKMP^i%(!uA);enM^ZGsIS|2J`A4ti9=o)V4#A!@ zq>hLASL_+t+5H!KkS+V)BLgI4wZVcJe2j8W9(5G{9jKK=QTpa56Cdy+#YfN2LmQf^ zNm1sO@lSU{tTq`}it|e&t^MaaarqTj(Zf7Zrh&}8U*EqV^uUqccMWb_dCGjmCS<+A z);-Y-gNbjPTIncuMr9PQm(+?lQ4LFL(vy}d?1Q)XY?_tusu!LcY)>bmrWH8X)ylD} z#dP-YrI#;{xjF-U>~Aco>+;Z%W5&Wq&IiP>hW@tay2NAUH*K(|V`ZGJXzzm3=Yg*J z!S@P2GhQWKI)j*ldGbtXM_OJ7%(`lq$e;7tE=c+_{2qLc!3q(Ox|~Pf#e%yx>cC2S zRoGNPa6S+(H_)QX5&FPd#Ia0IhUC&DY+RL!jUg4a=R{M!ZF*6E@9X5J2uBlg7C-7W z5__u!${%W0VGnqxaYn18c6TN|H5^u-a$rLke)67M+*xo3-uYD{%b`4F$L(v-^vgfi zKBXQlSvSJ>+28MofQu=OQ_+Dl3NX$fd~!YVnv$;LDiXe|;HPizQ58fCbjQxg-J9V- zsqtSVvi}4$6f`4*a{qZy?B9Rjzt?{l8&j0|yMn(DwESD}*P05klD~|%{4V(S7XM!b zJ0U^A|K0HaUC-|w-#<0oLT2H9>;L{P{Cj8cPhoUO0r78r!rw)IFX;a%8V_ka|L=SM zqrCsSmftIqe`<LFDNsVR{9d2@UBT~J+MfzUiT?3x{E@T$uI2Z5>`yJ(WdGWS-=nkN zHT<2I|C9#+7AXLL|6u9g#sBVF|0=Fd^%wE~b+n2ya1f0AnxH}f^g#jvI@(`X{{!AD Bg4_TA literal 0 HcmV?d00001 diff --git a/eu_basynthec/sourceTest/examples/~$Metabolomics2-Example.xlsx b/eu_basynthec/sourceTest/examples/~$Metabolomics2-Example.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..24f29bb860948c7c5f82a89ff6bfd4ff17ce621a GIT binary patch literal 171 mcmZQe(M>8YPE{ZgurZ`C=rSZR6a!%@g944Az^uDIin#y}(h}+b literal 0 HcmV?d00001 diff --git a/eu_basynthec/sourceTest/java/eu/basynthec/cisd/dss/metabolomics/MetabolomicsDataSetRegistrator2Test.java b/eu_basynthec/sourceTest/java/eu/basynthec/cisd/dss/metabolomics/MetabolomicsDataSetRegistrator2Test.java new file mode 100644 index 00000000000..abefb863e13 --- /dev/null +++ b/eu_basynthec/sourceTest/java/eu/basynthec/cisd/dss/metabolomics/MetabolomicsDataSetRegistrator2Test.java @@ -0,0 +1,80 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.basynthec.cisd.dss.metabolomics; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Properties; + +import org.testng.annotations.Test; + +import ch.systemsx.cisd.common.test.RecordingMatcher; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; +import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; +import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty; + +import eu.basynthec.cisd.dss.AbstractBaSynthecDataSetRegistratorTest; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public class MetabolomicsDataSetRegistrator2Test extends AbstractBaSynthecDataSetRegistratorTest +{ + private static final DataSetType DATA_SET_TYPE = new DataSetType("METABOLITE_INTENSITIES"); + + @Test + public void testSimpleTransaction() throws IOException + { + setUpHomeDataBaseExpectations(); + Properties properties = createThreadProperties(); + createHandler(properties, false, true); + createData("Metabolomics-Example.xlsx"); + + final RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails> atomicOperationDetails = + setUpDataSetRegistrationExpectations(DATA_SET_TYPE, TSV_DATA_SET_TYPE); + + handler.handle(markerFile); + + assertEquals(3, atomicOperationDetails.recordedObject().getDataSetRegistrations().size()); + + checkDataTypeProperty(atomicOperationDetails.recordedObject().getDataSetRegistrations() + .get(1), "METABOLITE_INTENSITIES"); + checkDataTypeProperty(atomicOperationDetails.recordedObject().getDataSetRegistrations() + .get(2), "METABOLITE_INTENSITIES"); + + NewExternalData dataSet = + atomicOperationDetails.recordedObject().getDataSetRegistrations().get(0); + + assertEquals(DATA_SET_CODE, dataSet.getCode()); + assertEquals(DATA_SET_TYPE, dataSet.getDataSetType()); + + HashMap<String, NewProperty> propertyMap = + getDataSetPropertiesMap(dataSet.getDataSetProperties()); + NewProperty strainProperty = propertyMap.get(STRAIN_NAMES_PROP); + + assertNotNull(strainProperty); + assert null != strainProperty; + assertEquals("CHASSIS 1", strainProperty.getValue()); + context.assertIsSatisfied(); + } + + @Override + protected String getRegistrationScriptsFolderPath() + { + return "dist/etc/metabolomics/"; + } +} diff --git a/eu_basynthec/sourceTest/java/eu/basynthec/cisd/dss/metabolomics/MetabolomicsValidator2Test.java b/eu_basynthec/sourceTest/java/eu/basynthec/cisd/dss/metabolomics/MetabolomicsValidator2Test.java new file mode 100644 index 00000000000..270c82379de --- /dev/null +++ b/eu_basynthec/sourceTest/java/eu/basynthec/cisd/dss/metabolomics/MetabolomicsValidator2Test.java @@ -0,0 +1,66 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.basynthec.cisd.dss.metabolomics; + +import java.io.File; +import java.util.List; + +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.validation.ValidationError; +import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.validation.ValidationScriptRunner; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public class MetabolomicsValidator2Test extends AssertJUnit +{ + private static final String[] VALIDATION_SCRIPT_PATH = new String[] + { "dist/etc/shared/shared-classes.py", "dist/etc/metabolomics2/data-set-validator.py" }; + + @Test + public void testGoodData() + { + ValidationScriptRunner scriptRunner = + ValidationScriptRunner.createValidatorFromScriptPaths(VALIDATION_SCRIPT_PATH); + List<ValidationError> errors = + scriptRunner.validate(new File("sourceTest/examples/Metabolomics2-Example.xlsx")); + assertTrue("The example should have no errors", errors.isEmpty()); + } + + @Test + public void testTemplate() + { + ValidationScriptRunner scriptRunner = + ValidationScriptRunner.createValidatorFromScriptPaths(VALIDATION_SCRIPT_PATH); + List<ValidationError> errors = + scriptRunner.validate(new File("sourceTest/examples/Metabolomics2-Template.xlsx")); + System.out.println(errors); + assertEquals("The template should have seven errors", 7, errors.size()); + } + + @Test + public void testBadData() + { + ValidationScriptRunner scriptRunner = + ValidationScriptRunner.createValidatorFromScriptPaths(VALIDATION_SCRIPT_PATH); + List<ValidationError> errors = + scriptRunner.validate(new File("sourceTest/examples/Metabolomics2-BadData.xlsx")); + assertEquals("The bad data should have seven errors", 7, errors.size()); + } +} -- GitLab