diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py index 045c5002d17e55e9b9c612a5709332212dfcfae1..dc7a7da08271ef72a9210aa597ab42a2afb85d6a 100644 --- a/src/caosdb/common/models.py +++ b/src/caosdb/common/models.py @@ -652,7 +652,7 @@ class Entity(object): if self.description is not None: xml.set("description", str(self.description)) - if self.value is not None and self.value != "": + if self.value is not None: if isinstance(self.value, Entity): if self.value.id is not None: xml.text = str(self.value.id) @@ -671,11 +671,15 @@ class Entity(object): v_elem.text = str(v.name) else: v_elem.text = str(v) + elif v == "": + v_elem.append(etree.Element("EmptyString")) elif v is None: pass else: v_elem.text = str(v) xml.append(v_elem) + elif self.value == "": + xml.append(etree.Element("EmptyString")) else: xml.text = str(self.value) @@ -943,33 +947,31 @@ class Entity(object): def _parse_col_values(cdt, vals): matcher = re.compile(r"^(?P<col>[^<]+)<(?P<dt>[^>]+)>$") m = matcher.match(cdt) - try: - if m: - col = m.group("col") - dt = m.group("dt") + if m: + col = m.group("col") + dt = m.group("dt") - if col == "LIST": - ret = list() - add = ret.append - else: - return vals + if col == "LIST": + ret = list() + add = ret.append + else: + return vals - for v in vals: - if dt == DOUBLE: - add(float(v)) - elif dt == TEXT or dt == DATETIME: + for v in vals: + if dt == DOUBLE: + add(float(v)) + elif dt == TEXT or dt == DATETIME: + add(v) + else: + try: + add(int(v)) + except BaseException: add(v) - else: - try: - add(int(v)) - except BaseException: - add(v) - - return ret - except BaseException: - traceback.print_exc(file=sys.stderr) + return ret + if len(vals) == 1: + return vals[0] return vals @@ -3560,10 +3562,13 @@ def _parse_single_xml_element(elem): Entity._from_xml(entity, elem) return entity + elif elem.tag.lower() == "emptystring": + return "" elif elem.tag.lower() == "value": - if elem.text is None: + if len(elem) == 1 and elem[0].tag.lower() == "emptystring": + return "" + elif elem.text is None or elem.text.strip() == "": return None - return str(elem.text.strip()) elif elem.tag.lower() == "querytemplate": return QueryTemplate._from_xml(elem) diff --git a/unittests/record.py b/unittests/record.py index ac20f1ce08b249035c1ebd0f64d41bdb8f7ac346..22e7676bbd50cf060f534e655bc29dd2b512a0bc 100644 --- a/unittests/record.py +++ b/unittests/record.py @@ -27,8 +27,85 @@ import caosdb as db from lxml import etree - # This is Record ID 171179 from the current CaosDB -testrecord = db.Record._from_xml(db.Record(), etree.fromstring(""" -<Record id="171179"><TransactionBenchmark>\n </TransactionBenchmark><Parent id="163454" name="LeapExperiment" description="Experiment for the LEAP project."/><Property id="163414" name="experimentId" description="A unique identifier for experiments" datatype="TEXT" importance="FIX" flag="inheritance:FIX">KCdSYWJiaXQnLCAnZXhfdml2bycsICdzeW5jaHJvbml6YXRpb25fbWFwJywgTm9uZSwgJzIwMTctMDgtMTEnLCBOb25lLCBOb25lKQ==</Property><Property id="163442" name="date" description="A calendar date. When something took place." datatype="DATETIME" importance="FIX" flag="inheritance:FIX">2017-08-11</Property><Property id="163399" name="vivoness" description="How the experiment was done: IN_VIVO or EX_VIVO." datatype="TEXT" importance="FIX" flag="inheritance:FIX">ex_vivo</Property><Property id="163418" name="species" description="The species of the experimental animal." datatype="TEXT" importance="FIX" flag="inheritance:FIX">Rabbit</Property><Property id="163449" name="ExperimentSeries" description="A collection of [Experiment] records which have the same [aim]." datatype="ExperimentSeries" importance="FIX" flag="inheritance:FIX">163386</Property><Property id="163397" name="MultiRecRecording" datatype="LIST<MultiRecRecording>" importance="FIX" flag="inheritance:FIX"><Value>171242</Value><Value>170651</Value><Value>171701</Value><Value>172074</Value><Value>171408</Value><Value>171687</Value><Value>170791</Value><Value>171115</Value><Value>171893</Value><Value>171237</Value><Value>171309</Value><Value>170899</Value><Value>171048</Value><Value>171077</Value><Value>171723</Value><Value>171085</Value><Value>171812</Value><Value>171829</Value><Value>171669</Value><Value>170695</Value><Value>170875</Value><Value>171751</Value><Value>171412</Value><Value>172204</Value><Value>170997</Value><Value>171490</Value><Value>171504</Value><Value>170977</Value><Value>171895</Value><Value>172233</Value><Value>171261</Value><Value>171318</Value><Value>171014</Value><Value>171132</Value><Value>171575</Value><Value>172217</Value><Value>171638</Value><Value>170656</Value><Value>171927</Value><Value>172232</Value><Value>171864</Value><Value>171564</Value><Value>171090</Value><Value>171633</Value><Value>171456</Value><Value>171755</Value><Value>170641</Value><Value>172144</Value><Value>171872</Value><Value>171619</Value><Value>171180</Value><Value>172019</Value><Value>171193</Value><Value>171069</Value><Value>171643</Value><Value>171789</Value><Value>170785</Value><Value>170904</Value><Value>171130</Value><Value>171098</Value><Value>171241</Value><Value>171796</Value><Value>171776</Value><Value>171175</Value><Value>171112</Value><Value>171514</Value><Value>171854</Value><Value>170962</Value><Value>171818</Value><Value>170745</Value><Value>171149</Value><Value>170639</Value><Value>171508</Value><Value>170800</Value><Value>171141</Value><Value>171414</Value><Value>171325</Value><Value>172168</Value><Value>171184</Value><Value>172083</Value><Value>172029</Value><Value>171556</Value><Value>172195</Value><Value>170789</Value><Value>171300</Value><Value>172230</Value><Value>171720</Value><Value>171341</Value><Value>171937</Value><Value>171673</Value><Value>172106</Value><Value>171281</Value><Value>171897</Value><Value>171108</Value><Value>172014</Value><Value>170867</Value><Value>171531</Value><Value>171674</Value><Value>172077</Value><Value>170944</Value><Value>171228</Value><Value>172207</Value><Value>171039</Value><Value>171778</Value><Value>170794</Value><Value>171646</Value><Value>172027</Value><Value>171279</Value><Value>171618</Value><Value>171233</Value><Value>170811</Value><Value>171357</Value><Value>172180</Value><Value>171585</Value><Value>170774</Value><Value>171625</Value><Value>171310</Value><Value>171855</Value><Value>172084</Value><Value>171395</Value><Value>171955</Value><Value>172216</Value><Value>171705</Value><Value>171312</Value><Value>171659</Value><Value>172192</Value><Value>171157</Value><Value>171978</Value><Value>170707</Value><Value>171250</Value><Value>171929</Value><Value>171709</Value><Value>170898</Value><Value>170723</Value><Value>172060</Value><Value>171693</Value><Value>172036</Value><Value>172162</Value><Value>171460</Value><Value>172065</Value><Value>171174</Value><Value>171461</Value><Value>172093</Value><Value>171200</Value><Value>172007</Value><Value>172102</Value><Value>171368</Value><Value>171761</Value><Value>172157</Value><Value>171354</Value><Value>170698</Value><Value>171254</Value><Value>171740</Value><Value>171303</Value><Value>170874</Value><Value>171248</Value><Value>171698</Value><Value>171191</Value><Value>171948</Value><Value>171920</Value><Value>171319</Value><Value>170649</Value><Value>171731</Value><Value>170643</Value><Value>171007</Value><Value>172186</Value><Value>171831</Value><Value>172128</Value><Value>172154</Value><Value>170841</Value><Value>171530</Value><Value>171142</Value><Value>171857</Value><Value>170982</Value><Value>171852</Value><Value>171574</Value><Value>171136</Value><Value>172107</Value><Value>171819</Value><Value>171746</Value><Value>171036</Value><Value>171331</Value><Value>170682</Value><Value>171779</Value><Value>171747</Value><Value>171383</Value><Value>170748</Value><Value>170691</Value><Value>170820</Value><Value>170829</Value><Value>171888</Value><Value>172098</Value><Value>172199</Value><Value>171290</Value><Value>170935</Value><Value>171056</Value><Value>171131</Value><Value>171415</Value><Value>171105</Value><Value>171135</Value><Value>171371</Value><Value>171640</Value><Value>171534</Value><Value>171012</Value><Value>172047</Value><Value>172081</Value><Value>171666</Value><Value>172089</Value><Value>172063</Value><Value>171449</Value><Value>171159</Value><Value>171808</Value><Value>171932</Value><Value>170664</Value><Value>172000</Value><Value>171220</Value><Value>170955</Value><Value>170740</Value><Value>171350</Value><Value>171528</Value><Value>171081</Value><Value>171199</Value><Value>171711</Value><Value>171446</Value><Value>171607</Value><Value>171292</Value><Value>170762</Value><Value>171896</Value><Value>170810</Value><Value>170990</Value><Value>171332</Value><Value>171080</Value><Value>171075</Value><Value>172130</Value><Value>171525</Value><Value>171993</Value><Value>172091</Value><Value>171924</Value><Value>172153</Value><Value>170661</Value><Value>171190</Value><Value>171021</Value><Value>172158</Value><Value>171980</Value><Value>171480</Value><Value>171598</Value><Value>171827</Value><Value>172166</Value><Value>171392</Value><Value>171512</Value><Value>171008</Value><Value>171610</Value><Value>171692</Value><Value>171908</Value><Value>171733</Value><Value>170866</Value><Value>171100</Value></Property><Property id="163401" name="PulsarProtocolLog" description="A log from Pulsar. This is the generic super type. Sub types will represent the log of a particular protocol." datatype="LIST<PulsarProtocolLog>" importance="FIX" flag="inheritance:FIX"><Value>171750</Value><Value>171019</Value><Value>171765</Value><Value>171269</Value><Value>170700</Value><Value>171665</Value><Value>171496</Value><Value>170954</Value><Value>170780</Value><Value>171313</Value><Value>171202</Value></Property><Property id="163429" name="ACQRawData" description="A file which is the direct/raw output of Acqknowledge." datatype="ACQRawData" importance="FIX" flag="inheritance:FIX">45506</Property><Property id="163456" name="syncMapValuesFiles" description="DESCRIBE ME!" datatype="LIST<FILE>" importance="FIX" flag="inheritance:FIX"><Value>45508</Value><Value>45509</Value><Value>45510</Value><Value>45511</Value><Value>45512</Value><Value>45513</Value><Value>45514</Value><Value>45515</Value><Value>45516</Value><Value>45517</Value><Value>45518</Value><Value>45519</Value><Value>45520</Value><Value>45521</Value><Value>45522</Value><Value>45523</Value><Value>45524</Value><Value>45525</Value><Value>45526</Value><Value>45527</Value><Value>45528</Value><Value>45529</Value><Value>45530</Value><Value>45531</Value><Value>45532</Value></Property></Record> +testrecord1 = db.Record._from_xml(db.Record(), etree.fromstring("""<Record id="171179"><TransactionBenchmark></TransactionBenchmark><Parent id="163454" name="LeapExperiment" description="Experiment for the LEAP project."/><Property id="163414" name="experimentId" description="A unique identifier for experiments" datatype="TEXT" importance="FIX" flag="inheritance:FIX">KCdSYWJiaXQnLCAnZXhfdml2bycsICdzeW5jaHJvbml6YXRpb25fbWFwJywgTm9uZSwgJzIwMTctMDgtMTEnLCBOb25lLCBOb25lKQ==</Property><Property id="568765" name="LISTofTEXT" datatype="LIST<TEXT>" importance="FIX"><Value>One</Value><Value>Two</Value><Value>Three</Value><Value></Value><Value><EmptyString/></Value></Property><Property id="568765" name="EMPTYTEXT1" datatype="TEXT" importance="FIX"><Value><EmptyString/></Value></Property><Property id="568765" name="EMPTYTEXT2" datatype="TEXT" importance="FIX"><EmptyString/></Property><Property id="568765" name="NULLTEXT1" datatype="TEXT" importance="FIX"></Property><Property id="568765" name="NULLTEXT2" datatype="TEXT" importance="FIX"><Value></Value></Property><Property id="163442" name="date" description="A calendar date. When something took place." datatype="DATETIME" importance="FIX" flag="inheritance:FIX">2017-08-11</Property><Property id="163399" name="vivoness" description="How the experiment was done: IN_VIVO or EX_VIVO." datatype="TEXT" importance="FIX" flag="inheritance:FIX">ex_vivo</Property><Property id="163418" name="species" description="The species of the experimental animal." datatype="TEXT" importance="FIX" flag="inheritance:FIX">Rabbit</Property><Property id="163449" name="ExperimentSeries" description="A collection of [Experiment] records which have the same [aim]." datatype="ExperimentSeries" importance="FIX" flag="inheritance:FIX">163386</Property><Property id="163397" name="MultiRecRecording" datatype="LIST<MultiRecRecording>" importance="FIX" flag="inheritance:FIX"><Value>171242</Value><Value>170651</Value><Value>171701</Value><Value>172074</Value><Value>171408</Value><Value>171687</Value><Value>170791</Value><Value>171115</Value><Value>171893</Value><Value>171237</Value><Value>171309</Value><Value>170899</Value><Value>171048</Value><Value>171077</Value><Value>171723</Value><Value>171085</Value><Value>171812</Value><Value>171829</Value><Value>171669</Value><Value>170695</Value><Value>170875</Value><Value>171751</Value><Value>171412</Value><Value>172204</Value><Value>170997</Value><Value>171490</Value><Value>171504</Value><Value>170977</Value><Value>171895</Value><Value>172233</Value><Value>171261</Value><Value>171318</Value><Value>171014</Value><Value>171132</Value><Value>171575</Value><Value>172217</Value><Value>171638</Value><Value>170656</Value><Value>171927</Value><Value>172232</Value><Value>171864</Value><Value>171564</Value><Value>171090</Value><Value>171633</Value><Value>171456</Value><Value>171755</Value><Value>170641</Value><Value>172144</Value><Value>171872</Value><Value>171619</Value><Value>171180</Value><Value>172019</Value><Value>171193</Value><Value>171069</Value><Value>171643</Value><Value>171789</Value><Value>170785</Value><Value>170904</Value><Value>171130</Value><Value>171098</Value><Value>171241</Value><Value>171796</Value><Value>171776</Value><Value>171175</Value><Value>171112</Value><Value>171514</Value><Value>171854</Value><Value>170962</Value><Value>171818</Value><Value>170745</Value><Value>171149</Value><Value>170639</Value><Value>171508</Value><Value>170800</Value><Value>171141</Value><Value>171414</Value><Value>171325</Value><Value>172168</Value><Value>171184</Value><Value>172083</Value><Value>172029</Value><Value>171556</Value><Value>172195</Value><Value>170789</Value><Value>171300</Value><Value>172230</Value><Value>171720</Value><Value>171341</Value><Value>171937</Value><Value>171673</Value><Value>172106</Value><Value>171281</Value><Value>171897</Value><Value>171108</Value><Value>172014</Value><Value>170867</Value><Value>171531</Value><Value>171674</Value><Value>172077</Value><Value>170944</Value><Value>171228</Value><Value>172207</Value><Value>171039</Value><Value>171778</Value><Value>170794</Value><Value>171646</Value><Value>172027</Value><Value>171279</Value><Value>171618</Value><Value>171233</Value><Value>170811</Value><Value>171357</Value><Value>172180</Value><Value>171585</Value><Value>170774</Value><Value>171625</Value><Value>171310</Value><Value>171855</Value><Value>172084</Value><Value>171395</Value><Value>171955</Value><Value>172216</Value><Value>171705</Value><Value>171312</Value><Value>171659</Value><Value>172192</Value><Value>171157</Value><Value>171978</Value><Value>170707</Value><Value>171250</Value><Value>171929</Value><Value>171709</Value><Value>170898</Value><Value>170723</Value><Value>172060</Value><Value>171693</Value><Value>172036</Value><Value>172162</Value><Value>171460</Value><Value>172065</Value><Value>171174</Value><Value>171461</Value><Value>172093</Value><Value>171200</Value><Value>172007</Value><Value>172102</Value><Value>171368</Value><Value>171761</Value><Value>172157</Value><Value>171354</Value><Value>170698</Value><Value>171254</Value><Value>171740</Value><Value>171303</Value><Value>170874</Value><Value>171248</Value><Value>171698</Value><Value>171191</Value><Value>171948</Value><Value>171920</Value><Value>171319</Value><Value>170649</Value><Value>171731</Value><Value>170643</Value><Value>171007</Value><Value>172186</Value><Value>171831</Value><Value>172128</Value><Value>172154</Value><Value>170841</Value><Value>171530</Value><Value>171142</Value><Value>171857</Value><Value>170982</Value><Value>171852</Value><Value>171574</Value><Value>171136</Value><Value>172107</Value><Value>171819</Value><Value>171746</Value><Value>171036</Value><Value>171331</Value><Value>170682</Value><Value>171779</Value><Value>171747</Value><Value>171383</Value><Value>170748</Value><Value>170691</Value><Value>170820</Value><Value>170829</Value><Value>171888</Value><Value>172098</Value><Value>172199</Value><Value>171290</Value><Value>170935</Value><Value>171056</Value><Value>171131</Value><Value>171415</Value><Value>171105</Value><Value>171135</Value><Value>171371</Value><Value>171640</Value><Value>171534</Value><Value>171012</Value><Value>172047</Value><Value>172081</Value><Value>171666</Value><Value>172089</Value><Value>172063</Value><Value>171449</Value><Value>171159</Value><Value>171808</Value><Value>171932</Value><Value>170664</Value><Value>172000</Value><Value>171220</Value><Value>170955</Value><Value>170740</Value><Value>171350</Value><Value>171528</Value><Value>171081</Value><Value>171199</Value><Value>171711</Value><Value>171446</Value><Value>171607</Value><Value>171292</Value><Value>170762</Value><Value>171896</Value><Value>170810</Value><Value>170990</Value><Value>171332</Value><Value>171080</Value><Value>171075</Value><Value>172130</Value><Value>171525</Value><Value>171993</Value><Value>172091</Value><Value>171924</Value><Value>172153</Value><Value>170661</Value><Value>171190</Value><Value>171021</Value><Value>172158</Value><Value>171980</Value><Value>171480</Value><Value>171598</Value><Value>171827</Value><Value>172166</Value><Value>171392</Value><Value>171512</Value><Value>171008</Value><Value>171610</Value><Value>171692</Value><Value>171908</Value><Value>171733</Value><Value>170866</Value><Value>171100</Value></Property><Property id="163401" name="PulsarProtocolLog" description="A log from Pulsar. This is the generic super type. Sub types will represent the log of a particular protocol." datatype="LIST<PulsarProtocolLog>" importance="FIX" flag="inheritance:FIX"><Value>171750</Value><Value>171019</Value><Value>171765</Value><Value>171269</Value><Value>170700</Value><Value>171665</Value><Value>171496</Value><Value>170954</Value><Value>170780</Value><Value>171313</Value><Value>171202</Value></Property><Property id="163429" name="ACQRawData" description="A file which is the direct/raw output of Acqknowledge." datatype="ACQRawData" importance="FIX" flag="inheritance:FIX">45506</Property><Property id="163456" name="syncMapValuesFiles" description="DESCRIBE ME!" datatype="LIST<FILE>" importance="FIX" flag="inheritance:FIX"><Value>45508</Value><Value>45509</Value><Value>45510</Value><Value>45511</Value><Value>45512</Value><Value>45513</Value><Value>45514</Value><Value>45515</Value><Value>45516</Value><Value>45517</Value><Value>45518</Value><Value>45519</Value><Value>45520</Value><Value>45521</Value><Value>45522</Value><Value>45523</Value><Value>45524</Value><Value>45525</Value><Value>45526</Value><Value>45527</Value><Value>45528</Value><Value>45529</Value><Value>45530</Value><Value>45531</Value><Value>45532</Value></Property></Record> """)) + +testrecord2 = db.Record._from_xml(db.Record(), etree.fromstring( +"""<Record id="43742"> + <Permissions> + <Permission name="USE:AS_REFERENCE" /> + <Permission name="USE:AS_DATA_TYPE" /> + <Permission name="RETRIEVE:ENTITY" /> + <Permission name="UPDATE:DESCRIPTION" /> + <Permission name="UPDATE:FILE:ADD" /> + <Permission name="UPDATE:FILE:MOVE" /> + <Permission name="RETRIEVE:ACL" /> + <Permission name="DELETE" /> + <Permission name="RETRIEVE:OWNER" /> + <Permission name="UPDATE:PROPERTY:ADD" /> + <Permission name="UPDATE:ROLE" /> + <Permission name="UPDATE:PARENT:ADD" /> + <Permission name="RETRIEVE:FILE" /> + <Permission name="USE:AS_PROPERTY" /> + <Permission name="UPDATE:PARENT:REMOVE" /> + <Permission name="USE:AS_PARENT" /> + <Permission name="UPDATE:PROPERTY:REMOVE" /> + <Permission name="UPDATE:NAME" /> + <Permission name="UPDATE:DATA_TYPE" /> + <Permission name="UPDATE:VALUE" /> + <Permission name="RETRIEVE:HISTORY" /> + <Permission name="EDIT:ACL" /> + <Permission name="UPDATE:FILE:REMOVE" /> + <Permission name="UPDATE:QUERY_TEMPLATE_DEFINITION" /> + </Permissions> + <Parent id="43740" name="TestRT" /> + <Property id="43741" name="TestProp" datatype="TEXT" importance="FIX"> + a string + <Permissions> + <Permission name="USE:AS_REFERENCE" /> + <Permission name="USE:AS_DATA_TYPE" /> + <Permission name="RETRIEVE:ENTITY" /> + <Permission name="UPDATE:DESCRIPTION" /> + <Permission name="UPDATE:FILE:ADD" /> + <Permission name="UPDATE:FILE:MOVE" /> + <Permission name="RETRIEVE:ACL" /> + <Permission name="DELETE" /> + <Permission name="RETRIEVE:OWNER" /> + <Permission name="UPDATE:PROPERTY:ADD" /> + <Permission name="UPDATE:ROLE" /> + <Permission name="UPDATE:PARENT:ADD" /> + <Permission name="RETRIEVE:FILE" /> + <Permission name="USE:AS_PROPERTY" /> + <Permission name="UPDATE:PARENT:REMOVE" /> + <Permission name="USE:AS_PARENT" /> + <Permission name="UPDATE:PROPERTY:REMOVE" /> + <Permission name="UPDATE:NAME" /> + <Permission name="UPDATE:DATA_TYPE" /> + <Permission name="UPDATE:VALUE" /> + <Permission name="RETRIEVE:HISTORY" /> + <Permission name="EDIT:ACL" /> + <Permission name="UPDATE:FILE:REMOVE" /> + <Permission name="UPDATE:QUERY_TEMPLATE_DEFINITION" /> + </Permissions> + </Property> + </Record>""")) + + +def test_null_empty_text_value_1(): + assert testrecord1.get_property("LISTofTEXT").value == ["One", "Two", "Three", None, ""] + +def test_null_empty_text_value_2(): + assert testrecord1.get_property("NULLTEXT1").value == None + +def test_null_empty_text_value_3(): + assert testrecord1.get_property("NULLTEXT2").value == None + +def test_null_empty_text_value_4(): + assert testrecord1.get_property("EMPTYTEXT1").value == "" + +def test_null_empty_text_value_5(): + assert testrecord1.get_property("EMPTYTEXT2").value == "" + +def test_string_value(): + testrecord2.get_property("TestProp").value == "a string" diff --git a/unittests/test_datatype.py b/unittests/test_datatype.py index 5a543100c8617374e0f075abf3adbdb2f8044129..09b9557285f1243b00b97d600cc11ccdfa685ade 100644 --- a/unittests/test_datatype.py +++ b/unittests/test_datatype.py @@ -1,5 +1,8 @@ from caosdb import LIST +from caosdb import RecordType def test_list(): assert LIST("RT") == "LIST<RT>" + assert LIST(RecordType("bla")) == "LIST<bla>" +