test_property.py 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  1. import unittest
  2. import datetime
  3. from odml import Property, Section, Document, DType
  4. from odml.property import BaseProperty
  5. from odml.section import BaseSection
  6. class TestProperty(unittest.TestCase):
  7. def test_simple_attributes(self):
  8. p_name = "propertyName"
  9. p_origin = "from over there"
  10. p_unit = "pears"
  11. p_uncertainty = "12"
  12. p_ref = "4 8 15 16 23"
  13. p_def = "an odml test property"
  14. p_dep = "yes"
  15. p_dep_val = "42"
  16. prop = Property(name=p_name, value_origin=p_origin, unit=p_unit,
  17. uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
  18. dependency=p_dep, dependency_value=p_dep_val)
  19. self.assertEqual(prop.name, p_name)
  20. self.assertEqual(prop.value_origin, p_origin)
  21. self.assertEqual(prop.unit, p_unit)
  22. self.assertEqual(prop.uncertainty, p_uncertainty)
  23. self.assertEqual(prop.reference, p_ref)
  24. self.assertEqual(prop.definition, p_def)
  25. self.assertEqual(prop.dependency, p_dep)
  26. self.assertEqual(prop.dependency_value, p_dep_val)
  27. # Test setting attributes
  28. prop.name = "%s_edit" % p_name
  29. self.assertEqual(prop.name, "%s_edit" % p_name)
  30. prop.value_origin = "%s_edit" % p_origin
  31. self.assertEqual(prop.value_origin, "%s_edit" % p_origin)
  32. prop.unit = "%s_edit" % p_unit
  33. self.assertEqual(prop.unit, "%s_edit" % p_unit)
  34. prop.uncertainty = 13
  35. self.assertEqual(prop.uncertainty, 13.0)
  36. prop.reference = "%s_edit" % p_ref
  37. self.assertEqual(prop.reference, "%s_edit" % p_ref)
  38. prop.definition = "%s_edit" % p_def
  39. self.assertEqual(prop.definition, "%s_edit" % p_def)
  40. prop.dependency = "%s_edit" % p_dep
  41. self.assertEqual(prop.dependency, "%s_edit" % p_dep)
  42. prop.dependency_value = "%s_edit" % p_dep_val
  43. self.assertEqual(prop.dependency_value, "%s_edit" % p_dep_val)
  44. # Test setting attributes to None when '' is passed.
  45. prop.value_origin = ""
  46. self.assertIsNone(prop.value_origin)
  47. prop.unit = ""
  48. self.assertIsNone(prop.unit)
  49. prop.uncertainty = ""
  50. self.assertIsNone(prop.uncertainty)
  51. prop.reference = ""
  52. self.assertIsNone(prop.reference)
  53. prop.definition = ""
  54. self.assertIsNone(prop.definition)
  55. prop.dependency = ""
  56. self.assertIsNone(prop.dependency)
  57. prop.dependency_value = ""
  58. self.assertIsNone(prop.dependency_value)
  59. def test_value(self):
  60. prop = Property("property", 100)
  61. self.assertEqual(prop.values[0], 100)
  62. self.assertIsInstance(prop.values, list)
  63. prop.values = None
  64. self.assertEqual(len(prop), 0)
  65. prop.values = [1, 2, 3]
  66. prop.values = ""
  67. self.assertEqual(len(prop), 0)
  68. prop.values = [1, 2, 3]
  69. prop.values = []
  70. self.assertEqual(len(prop), 0)
  71. prop.values = [1, 2, 3]
  72. prop.values = ()
  73. self.assertEqual(len(prop), 0)
  74. prop.values.append(5)
  75. self.assertEqual(len(prop.values), 0)
  76. prop2 = Property("test", {"name": "Marie"})
  77. self.assertEqual(len(prop2), 1)
  78. # Test tuple dtype value.
  79. prop_tuple = Property(name="Location", value='(39.12; 67.19)', dtype='2-tuple')
  80. tuple_value = prop_tuple.values[0] # As the formed tuple is a list of list
  81. self.assertEqual(tuple_value[0], '39.12')
  82. self.assertEqual(tuple_value[1], '67.19')
  83. # Test invalid tuple length
  84. with self.assertRaises(ValueError):
  85. _ = Property(name="Public-Key", value='(5689; 1254; 687)', dtype='2-tuple')
  86. prop3 = Property('myprop', value=0, dtype=DType.int)
  87. self.assertEqual(prop3.value, [0])
  88. self.assertEqual(prop3.values, [0])
  89. prop4 = Property('myprop', value=0, dtype=DType.boolean)
  90. self.assertEqual(prop4.value, [False])
  91. self.assertEqual(prop4.values, [False])
  92. prop5 = Property('myprop', value=0)
  93. self.assertEqual(prop5.value, [0])
  94. self.assertEqual(prop5.values, [0])
  95. with self.assertRaises(ValueError):
  96. Property(name="dateprop", dtype=DType.date, value=['20190707'])
  97. with self.assertRaises(ValueError):
  98. Property(name="timeprop", dtype=DType.time, value=['11.11.11'])
  99. with self.assertRaises(ValueError):
  100. Property(name="datetimeprop", dtype=DType.datetime, value=['20190707'])
  101. with self.assertRaises(ValueError):
  102. Property(name="intprop", dtype=DType.int, value=[2, "Hello!", 4])
  103. prop6 = Property('myprop', values=["(8; 9; 10)", "(11; 12; 13)"], dtype="3-tuple")
  104. self.assertEqual(len(prop6.values), 2)
  105. prop7 = Property('myprop', values=[["0", "1", "2"], [3, 4, 5]], dtype="3-tuple")
  106. self.assertEqual(len(prop7.values), 2)
  107. prop8 = Property('myprop', values=["(8; 9; 10)", ["0", "1", "2"], [3, 4, 5]], dtype="3-tuple")
  108. self.assertEqual(len(prop8.values), 3)
  109. def test_value_append(self):
  110. # Test append w/o Property value or dtype
  111. prop = Property(name="append")
  112. prop.append(1)
  113. self.assertEqual(prop.dtype, DType.int)
  114. self.assertEqual(prop.values, [1])
  115. # Test append with Property dtype.
  116. prop = Property(name="append", dtype="int")
  117. prop.append(3)
  118. self.assertEqual(prop.values, [3])
  119. # Test append with Property value
  120. prop = Property(name="append", value=[1, 2])
  121. prop.append(3)
  122. self.assertEqual(prop.values, [1, 2, 3])
  123. # Test append with Property list value
  124. prop = Property(name="append", value=[1, 2])
  125. prop.append([3])
  126. self.assertEqual(prop.values, [1, 2, 3])
  127. # Test append of empty values, make sure 0 and False are properly handled
  128. prop = Property(name="append")
  129. prop.append(None)
  130. prop.append("")
  131. prop.append([])
  132. prop.append({})
  133. self.assertEqual(prop.values, [])
  134. prop.append(0)
  135. self.assertEqual(prop.values, [0])
  136. prop.values = None
  137. prop.dtype = None
  138. prop.append(False)
  139. self.assertEqual(prop.values, [False])
  140. prop = Property(name="append", value=[1, 2])
  141. prop.append(None)
  142. prop.append("")
  143. prop.append([])
  144. prop.append({})
  145. self.assertEqual(prop.values, [1, 2])
  146. prop.append(0)
  147. self.assertEqual(prop.values, [1, 2, 0])
  148. # Test fail append with multiple values
  149. prop = Property(name="append", value=[1, 2, 3])
  150. with self.assertRaises(ValueError):
  151. prop.append([4, 5])
  152. self.assertEqual(prop.values, [1, 2, 3])
  153. # Test fail append with mismatching dtype
  154. prop = Property(name="append", value=[1, 2], dtype="int")
  155. with self.assertRaises(ValueError):
  156. prop.append([3.14])
  157. with self.assertRaises(ValueError):
  158. prop.append([True])
  159. with self.assertRaises(ValueError):
  160. prop.append(["5.927"])
  161. self.assertEqual(prop.values, [1, 2])
  162. # Test strict flag
  163. prop.append(3.14, strict=False)
  164. prop.append(True, strict=False)
  165. prop.append("5.927", strict=False)
  166. self.assertEqual(prop.values, [1, 2, 3, 1, 5])
  167. # Make sure non-convertible values still raise an error
  168. with self.assertRaises(ValueError):
  169. prop.append("invalid")
  170. self.assertEqual(prop.values, [1, 2, 3, 1, 5])
  171. prop5 = Property("test", value="a string")
  172. prop5.append("Freude")
  173. self.assertEqual(len(prop5), 2)
  174. self.assertRaises(ValueError, prop5.append, "[a, b, c]")
  175. prop6 = Property(name="prop", value=["A Abraham", "B Barnes", "C Clark"],
  176. dtype=DType.person)
  177. prop6.append("D Dickins")
  178. self.assertEqual(len(prop6), 4)
  179. self.assertRaises(ValueError, prop6.append, 1)
  180. self.assertRaises(ValueError, prop6.append, 1.3)
  181. self.assertRaises(ValueError, prop6.append, True)
  182. prop7 = Property(name="prop", value=["https://en.wikipedia.org/wiki/Earth"],
  183. dtype=DType.url)
  184. prop7.append("https://en.wikipedia.org/wiki/Mars")
  185. self.assertEqual(len(prop7), 2)
  186. self.assertRaises(ValueError, prop7.append, 1)
  187. self.assertRaises(ValueError, prop7.append, 1.3)
  188. self.assertRaises(ValueError, prop7.append, True)
  189. prop8 = Property(name="prop", value=["Earth is No. 3."], dtype=DType.text)
  190. prop8.append("Mars is No. 4.")
  191. self.assertEqual(len(prop8), 2)
  192. self.assertRaises(ValueError, prop8.append, 1)
  193. self.assertRaises(ValueError, prop8.append, 1.3)
  194. self.assertRaises(ValueError, prop8.append, True)
  195. prop9 = Property(name="tuple-test", dtype="3-tuple", values="(1; 2; 3)")
  196. prop9.append("(7; 8; 9)")
  197. self.assertEqual(len(prop9), 2)
  198. self.assertRaises(ValueError, prop9.append, "(10; 11)")
  199. prop9.append([[2, 3, 4]])
  200. self.assertEqual(len(prop9), 3)
  201. self.assertRaises(ValueError, prop9.append, [[10, 11]])
  202. prop10 = Property(name="prop10", dtype="date", values=['2011-12-01', '2011-12-02'])
  203. with self.assertRaises(ValueError):
  204. prop10.append('2011-12-03', strict=True)
  205. self.assertEqual(prop10.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 2)])
  206. prop10.append('2011-12-03', strict=False)
  207. self.assertEqual(prop10.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 2),
  208. datetime.date(2011, 12, 3)])
  209. prop10.append([datetime.date(2011, 12, 4)], strict=True)
  210. self.assertEqual(prop10.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 2),
  211. datetime.date(2011, 12, 3), datetime.date(2011, 12, 4)])
  212. prop11 = Property(name="prop11", dtype="time", values=['12:00:01', '12:00:02'])
  213. with self.assertRaises(ValueError):
  214. prop11.append('12:00:03', strict=True)
  215. self.assertEqual(prop11.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 2)])
  216. prop11.append('12:00:03', strict=False)
  217. self.assertEqual(prop11.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 2),
  218. datetime.time(12, 0, 3)])
  219. prop11.append([datetime.time(12, 0, 4)], strict=True)
  220. self.assertEqual(prop11.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 2),
  221. datetime.time(12, 0, 3), datetime.time(12, 0, 4)])
  222. prop12 = Property(name="prop12", dtype="datetime",
  223. values=['2011-12-01 12:00:01', '2011-12-01 12:00:02'])
  224. with self.assertRaises(ValueError):
  225. prop12.append('2011-12-01 12:00:03', strict=True)
  226. self.assertEqual(prop12.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  227. datetime.datetime(2011, 12, 1, 12, 0, 2)])
  228. prop12.append('2011-12-01 12:00:03', strict=False)
  229. self.assertEqual(prop12.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  230. datetime.datetime(2011, 12, 1, 12, 0, 2),
  231. datetime.datetime(2011, 12, 1, 12, 0, 3)])
  232. prop12.append([datetime.datetime(2011, 12, 1, 12, 0, 4)], strict=True)
  233. self.assertEqual(prop12.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  234. datetime.datetime(2011, 12, 1, 12, 0, 2),
  235. datetime.datetime(2011, 12, 1, 12, 0, 3),
  236. datetime.datetime(2011, 12, 1, 12, 0, 4)])
  237. def test_value_extend(self):
  238. prop = Property(name="extend")
  239. # Test extend w/o Property value or dtype.
  240. val = [1, 2, 3]
  241. prop.extend(val)
  242. self.assertEqual(prop.dtype, DType.int)
  243. self.assertEqual(prop.values, val)
  244. # Extend with single value.
  245. prop.extend(4)
  246. self.assertEqual(prop.values, [1, 2, 3, 4])
  247. # Extend with list value.
  248. prop.extend([5, 6])
  249. self.assertEqual(prop.values, [1, 2, 3, 4, 5, 6])
  250. # Test extend w/o Property value
  251. prop = Property(name="extend", dtype="float")
  252. prop.extend([1.0, 2.0, 3.0])
  253. self.assertEqual(prop.values, [1.0, 2.0, 3.0])
  254. # Test extend with Property value
  255. prop = Property(name="extend", value=10)
  256. prop.extend([20, 30, '40'])
  257. self.assertEqual(prop.values, [10, 20, 30, 40])
  258. # Test extend fail with mismatching dtype
  259. with self.assertRaises(ValueError):
  260. prop.extend(['5', 6, 7])
  261. with self.assertRaises(ValueError):
  262. prop.extend([5, 6, 'a'])
  263. # Test extend via Property
  264. prop = Property(name="extend", value=["a", "b"])
  265. ext_prop = Property(name="value extend", value="c")
  266. prop.extend(ext_prop)
  267. self.assertEqual(prop.values, ["a", "b", "c"])
  268. ext_prop.values = ["d", "e"]
  269. prop.extend(ext_prop)
  270. self.assertEqual(prop.values, ["a", "b", "c", "d", "e"])
  271. ext_prop = Property(name="value extend", value=[1, 2, 3])
  272. with self.assertRaises(ValueError):
  273. prop.extend(ext_prop)
  274. self.assertEqual(prop.values, ["a", "b", "c", "d", "e"])
  275. # Test extend via Property unit check
  276. prop = Property(name="extend", value=[1, 2], unit="mV")
  277. ext_prop = Property(name="extend", value=[3, 4], unit="mV")
  278. prop.extend(ext_prop)
  279. self.assertEqual(prop.values, [1, 2, 3, 4])
  280. ext_prop.unit = "kV"
  281. with self.assertRaises(ValueError):
  282. prop.extend(ext_prop)
  283. self.assertEqual(prop.values, [1, 2, 3, 4])
  284. ext_prop.unit = ""
  285. with self.assertRaises(ValueError):
  286. prop.extend(ext_prop)
  287. self.assertEqual(prop.values, [1, 2, 3, 4])
  288. # Test strict flag
  289. prop = Property(name="extend", value=[1, 2], dtype="int")
  290. with self.assertRaises(ValueError):
  291. prop.extend([3.14, True, "5.927"])
  292. self.assertEqual(prop.values, [1, 2])
  293. prop.extend([3.14, True, "5.927"], strict=False)
  294. self.assertEqual(prop.values, [1, 2, 3, 1, 5])
  295. # Make sure non-convertible values still raise an error
  296. with self.assertRaises(ValueError):
  297. prop.extend([6, "some text"])
  298. prop1 = Property(name="prop", value=["A Abraham", "B Barnes", "C Clark"],
  299. dtype=DType.person)
  300. prop1.extend("D Dickins")
  301. self.assertEqual(len(prop1), 4)
  302. self.assertRaises(ValueError, prop1.extend, 1)
  303. self.assertRaises(ValueError, prop1.extend, 1.3)
  304. self.assertRaises(ValueError, prop1.extend, True)
  305. prop2 = Property(name="prop", value=["https://en.wikipedia.org/wiki/Earth"],
  306. dtype=DType.url)
  307. prop2.extend("https://en.wikipedia.org/wiki/Mars")
  308. self.assertEqual(len(prop2), 2)
  309. self.assertRaises(ValueError, prop2.extend, 1)
  310. self.assertRaises(ValueError, prop2.extend, 1.3)
  311. self.assertRaises(ValueError, prop2.extend, True)
  312. prop3 = Property(name="prop", value=["Earth is No. 3."], dtype=DType.text)
  313. prop3.extend("Mars is No. 4.")
  314. self.assertEqual(len(prop3), 2)
  315. self.assertRaises(ValueError, prop3.extend, 1)
  316. self.assertRaises(ValueError, prop3.extend, 1.3)
  317. self.assertRaises(ValueError, prop3.extend, True)
  318. prop4 = Property(name="tuple-test", dtype="3-tuple", values="(1; 2; 3)")
  319. prop4.extend(["(7; 8; 9)", "(10; 11; 12)"])
  320. self.assertEqual(len(prop4), 3)
  321. self.assertRaises(ValueError, prop4.extend, "(10; 11)")
  322. prop4.extend([[2, 3, 4], [5, 6, 7]])
  323. self.assertEqual(len(prop4), 5)
  324. self.assertRaises(ValueError, prop4.extend, [[10, 11]])
  325. prop4 = Property(name="prop4", dtype="date", values=['2011-12-01', '2011-12-02'])
  326. with self.assertRaises(ValueError):
  327. prop4.extend('2011-12-03', strict=True)
  328. self.assertEqual(prop4.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 2)])
  329. prop4.extend('2011-12-03', strict=False)
  330. self.assertEqual(prop4.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 2),
  331. datetime.date(2011, 12, 3)])
  332. prop4.extend([datetime.date(2011, 12, 4)], strict=True)
  333. self.assertEqual(prop4.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 2),
  334. datetime.date(2011, 12, 3), datetime.date(2011, 12, 4)])
  335. prop4.extend([datetime.date(2011, 12, 5), datetime.date(2011, 12, 6)], strict=True)
  336. self.assertEqual(prop4.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 2),
  337. datetime.date(2011, 12, 3), datetime.date(2011, 12, 4),
  338. datetime.date(2011, 12, 5), datetime.date(2011, 12, 6)])
  339. with self.assertRaises(ValueError):
  340. prop4.extend(['2011-12-03', 'abc'], strict=False)
  341. prop5 = Property(name="prop5", dtype="time", values=['12:00:01', '12:00:02'])
  342. with self.assertRaises(ValueError):
  343. prop5.extend('12:00:03', strict=True)
  344. self.assertEqual(prop5.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 2)])
  345. prop5.extend('12:00:03', strict=False)
  346. self.assertEqual(prop5.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 2),
  347. datetime.time(12, 0, 3)])
  348. prop5.extend([datetime.time(12, 0, 4)], strict=True)
  349. self.assertEqual(prop5.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 2),
  350. datetime.time(12, 0, 3), datetime.time(12, 0, 4)])
  351. prop5.extend([datetime.time(12, 0, 5), datetime.time(12, 0, 6)], strict=True)
  352. self.assertEqual(prop5.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 2),
  353. datetime.time(12, 0, 3), datetime.time(12, 0, 4),
  354. datetime.time(12, 0, 5), datetime.time(12, 0, 6)])
  355. with self.assertRaises(ValueError):
  356. prop4.extend(['12:00:07', 'abc'], strict=False)
  357. prop6 = Property(name="prop6", dtype="datetime",
  358. values=['2011-12-01 12:00:01', '2011-12-01 12:00:02'])
  359. with self.assertRaises(ValueError):
  360. prop6.extend('2011-12-01 12:00:03', strict=True)
  361. self.assertEqual(prop6.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  362. datetime.datetime(2011, 12, 1, 12, 0, 2)])
  363. prop6.extend('2011-12-01 12:00:03', strict=False)
  364. self.assertEqual(prop6.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  365. datetime.datetime(2011, 12, 1, 12, 0, 2),
  366. datetime.datetime(2011, 12, 1, 12, 0, 3)])
  367. prop6.extend([datetime.datetime(2011, 12, 1, 12, 0, 4)], strict=True)
  368. self.assertEqual(prop6.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  369. datetime.datetime(2011, 12, 1, 12, 0, 2),
  370. datetime.datetime(2011, 12, 1, 12, 0, 3),
  371. datetime.datetime(2011, 12, 1, 12, 0, 4)])
  372. prop6.extend([datetime.datetime(2011, 12, 1, 12, 0, 5),
  373. datetime.datetime(2011, 12, 1, 12, 0, 6)], strict=True)
  374. self.assertEqual(prop6.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  375. datetime.datetime(2011, 12, 1, 12, 0, 2),
  376. datetime.datetime(2011, 12, 1, 12, 0, 3),
  377. datetime.datetime(2011, 12, 1, 12, 0, 4),
  378. datetime.datetime(2011, 12, 1, 12, 0, 5),
  379. datetime.datetime(2011, 12, 1, 12, 0, 6)])
  380. with self.assertRaises(ValueError):
  381. prop4.extend(['2011-12-03 12:00:07', 'abc'], strict=False)
  382. def test_insert(self):
  383. prop1 = Property(name="prop1", dtype="int", values=[0,2])
  384. prop1.insert(1, 1)
  385. self.assertEqual(prop1.values, [0, 1, 2])
  386. prop1.insert(4, 3)
  387. self.assertEqual(prop1.values, [0, 1, 2, 3])
  388. with self.assertRaises(ValueError):
  389. prop1.append([4, 5])
  390. self.assertEqual(prop1.values, [0, 1, 2, 3])
  391. with self.assertRaises(ValueError):
  392. prop1.insert(1, 3.14)
  393. with self.assertRaises(ValueError):
  394. prop1.insert(1, True)
  395. with self.assertRaises(ValueError):
  396. prop1.insert(1, "5.927")
  397. self.assertEqual(prop1.values, [0, 1, 2, 3])
  398. prop2 = Property(name="prop2", dtype="int", values=[1, 2])
  399. prop2.insert(1, 3.14, strict=False)
  400. self.assertEqual(prop2.values, [1, 3, 2])
  401. prop2.insert(1, True, strict=False)
  402. self.assertEqual(prop2.values, [1, 1, 3, 2])
  403. prop2.insert(1, "5.927", strict=False)
  404. self.assertEqual(prop2.values, [1, 5, 1, 3, 2])
  405. prop3 = Property(name="prop3", dtype="string", values=["a", "c"])
  406. prop3.insert(1, "b")
  407. self.assertEqual(prop3.values, ["a", "b", "c"])
  408. prop3.insert(1, 1, strict=False)
  409. self.assertEqual(prop3.values, ["a", "1", "b", "c"])
  410. with self.assertRaises(ValueError):
  411. prop3.insert(1, 2, strict=True)
  412. self.assertEqual(prop3.values, ["a", "1", "b", "c"])
  413. prop4 = Property(name="prop4", dtype="float", values=[1.1, 1.3])
  414. prop4.insert(1, 1.2)
  415. self.assertEqual(prop4.values, [1.1, 1.2, 1.3])
  416. prop4.insert(1, 2, strict=False)
  417. self.assertEqual(prop4.values, [1.1, 2.0, 1.2, 1.3])
  418. with self.assertRaises(ValueError):
  419. prop4.insert(1, 2, strict=True)
  420. self.assertEqual(prop4.values, [1.1, 2.0, 1.2, 1.3])
  421. prop5 = Property(name="prop5", dtype="2-tuple", values=["(1; 2)", "(5; 6)"])
  422. prop5.insert(1, "(3; 4)", strict=True)
  423. self.assertEqual(prop5.values, [['1', '2'], ['3', '4'], ['5', '6']])
  424. prop5.insert(1, [['4', '5']], strict=True)
  425. self.assertEqual(prop5.values, [['1', '2'], ['4', '5'], ['3', '4'], ['5', '6']])
  426. prop6 = Property(name="prop6", dtype="boolean", values=[True, True])
  427. prop6.insert(1, False)
  428. self.assertEqual(prop6.values, [True, False, True])
  429. prop6.insert(1, 1, strict=False)
  430. self.assertEqual(prop6.values, [True, True, False, True])
  431. with self.assertRaises(ValueError):
  432. prop6.insert(1, 2, strict=False)
  433. self.assertEqual(prop6.values, [True, True, False, True])
  434. with self.assertRaises(ValueError):
  435. prop6.insert(1, 0, strict=True)
  436. self.assertEqual(prop6.values, [True, True, False, True])
  437. prop7 = Property(name="prop7", dtype="date", values=['2011-12-01', '2011-12-04'])
  438. with self.assertRaises(ValueError):
  439. prop7.insert(1, '2011-12-03', strict=True)
  440. self.assertEqual(prop7.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 4)])
  441. prop7.insert(1, '2011-12-03', strict=False)
  442. self.assertEqual(prop7.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 3),
  443. datetime.date(2011, 12, 4)])
  444. prop7.insert(1, [datetime.date(2011, 12, 2)], strict=True)
  445. self.assertEqual(prop7.values, [datetime.date(2011, 12, 1), datetime.date(2011, 12, 2),
  446. datetime.date(2011, 12, 3), datetime.date(2011, 12, 4)])
  447. prop8 = Property(name="prop8", dtype="time", values=['12:00:01', '12:00:04'])
  448. with self.assertRaises(ValueError):
  449. prop8.insert(1, '12:00:03', strict=True)
  450. self.assertEqual(prop8.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 4)])
  451. prop8.insert(1, '12:00:03', strict=False)
  452. self.assertEqual(prop8.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 3),
  453. datetime.time(12, 0, 4)])
  454. prop8.insert(1, [datetime.time(12, 0, 2)], strict=True)
  455. self.assertEqual(prop8.values, [datetime.time(12, 0, 1), datetime.time(12, 0, 2),
  456. datetime.time(12, 0, 3), datetime.time(12, 0, 4)])
  457. prop9 = Property(name="prop9", dtype="datetime",
  458. values=['2011-12-01 12:00:01', '2011-12-01 12:00:04'])
  459. with self.assertRaises(ValueError):
  460. prop9.insert(1, '2011-12-01 12:00:03', strict=True)
  461. self.assertEqual(prop9.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  462. datetime.datetime(2011, 12, 1, 12, 0, 4)])
  463. prop9.insert(1, '2011-12-01 12:00:03', strict=False)
  464. self.assertEqual(prop9.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  465. datetime.datetime(2011, 12, 1, 12, 0, 3),
  466. datetime.datetime(2011, 12, 1, 12, 0, 4)])
  467. prop9.insert(1, [datetime.datetime(2011, 12, 1, 12, 0, 2)], strict=True)
  468. self.assertEqual(prop9.values, [datetime.datetime(2011, 12, 1, 12, 0, 1),
  469. datetime.datetime(2011, 12, 1, 12, 0, 2),
  470. datetime.datetime(2011, 12, 1, 12, 0, 3),
  471. datetime.datetime(2011, 12, 1, 12, 0, 4)])
  472. prop10 = Property(name="prop", value=["Earth is\n No. 3."], dtype=DType.text)
  473. prop10.insert(1, "Mars is\n No. 4.", strict=False)
  474. self.assertEqual(len(prop10), 2)
  475. self.assertEqual(prop10.values, ["Earth is\n No. 3.", "Mars is\n No. 4."])
  476. prop10.insert(1, 'A new world emerged?', strict=True)
  477. self.assertEqual(prop10.values, ["Earth is\n No. 3.",
  478. "A new world emerged?",
  479. "Mars is\n No. 4."])
  480. prop10.insert(1, 1, strict=False)
  481. self.assertEqual(prop10.values, ["Earth is\n No. 3.", "1",
  482. "A new world emerged?",
  483. "Mars is\n No. 4."])
  484. with self.assertRaises(ValueError):
  485. prop10.insert(1, 1, strict=True)
  486. self.assertEqual(prop10.values, ["Earth is\n No. 3.", "1",
  487. "A new world emerged?",
  488. "Mars is\n No. 4."])
  489. def test_reorder(self):
  490. sec = Section()
  491. prop_zero = Property(name="prop_zero", parent=sec)
  492. prop_one = Property(name="prop_one", parent=sec)
  493. prop_two = Property(name="prop_two", parent=sec)
  494. prop_three = Property(name="prop_three", parent=sec)
  495. self.assertEqual(sec.properties[0].name, prop_zero.name)
  496. self.assertEqual(sec.properties[2].name, prop_two.name)
  497. prop_two.reorder(0)
  498. self.assertEqual(sec.properties[0].name, prop_two.name)
  499. self.assertEqual(sec.properties[1].name, prop_zero.name)
  500. self.assertEqual(sec.properties[2].name, prop_one.name)
  501. self.assertEqual(sec.properties[3].name, prop_three.name)
  502. prop_two.reorder(2)
  503. self.assertEqual(sec.properties[0].name, prop_zero.name)
  504. self.assertEqual(sec.properties[1].name, prop_one.name)
  505. self.assertEqual(sec.properties[2].name, prop_two.name)
  506. self.assertEqual(sec.properties[3].name, prop_three.name)
  507. # Test Exception on unconnected property
  508. prop = Property(name="main")
  509. with self.assertRaises(ValueError):
  510. prop.reorder(0)
  511. def test_get_set_value(self):
  512. values = [1, 2, 3, 4, 5]
  513. prop = Property("property", value=values)
  514. self.assertEqual(len(prop), 5)
  515. for lval, pval in zip(values, prop.values):
  516. self.assertEqual(lval, pval)
  517. count = 0
  518. for _ in prop:
  519. count += 1
  520. self.assertEqual(count, len(values))
  521. prop[0] = 10
  522. self.assertEqual(prop[0], 10)
  523. with self.assertRaises(ValueError):
  524. prop[1] = 'stringval'
  525. def test_bool_conversion(self):
  526. # Success tests
  527. prop = Property(name='received', value=[1, 0, 1, 0, 1])
  528. self.assertEqual(prop.dtype, 'int')
  529. prop.dtype = DType.boolean
  530. self.assertEqual(prop.dtype, 'boolean')
  531. self.assertEqual(prop.values, [True, False, True, False, True])
  532. prop = Property(name='sent', value=['False', True, 'TRUE', '0', 't', 'F', '1'])
  533. self.assertEqual(prop.dtype, 'string')
  534. prop.dtype = DType.boolean
  535. self.assertEqual(prop.dtype, 'boolean')
  536. self.assertEqual(prop.values, [False, True, True, False, True, False, True])
  537. # Failure tests
  538. curr_val = [3, 0, 1, 0, 8]
  539. curr_type = 'int'
  540. prop = Property(name='received', value=curr_val)
  541. self.assertEqual(prop.dtype, curr_type)
  542. with self.assertRaises(ValueError):
  543. prop.dtype = DType.boolean
  544. self.assertEqual(prop.dtype, curr_type)
  545. self.assertEqual(prop.values, curr_val)
  546. curr_type = 'string'
  547. prop = Property(name='sent', value=['False', True, 'TRUE', '0', 't', '12', 'Ft'])
  548. self.assertEqual(prop.dtype, curr_type)
  549. with self.assertRaises(ValueError):
  550. prop.dtype = DType.boolean
  551. self.assertEqual(prop.dtype, curr_type)
  552. def test_str_to_int_convert(self):
  553. # Success Test
  554. prop = Property(name='cats_onboard', value=['3', '0', '1', '0', '8'])
  555. self.assertEqual(prop.dtype, 'string')
  556. prop.dtype = DType.int
  557. self.assertEqual(prop.dtype, 'int')
  558. self.assertEqual(prop.values, [3, 0, 1, 0, 8])
  559. # Failure Test
  560. prop = Property(name='dogs_onboard', value=['7', '20', '1 Dog', 'Seven'])
  561. self.assertEqual(prop.dtype, 'string')
  562. with self.assertRaises(ValueError):
  563. prop.dtype = DType.int
  564. self.assertEqual(prop.dtype, 'string')
  565. self.assertEqual(prop.values, ['7', '20', '1 Dog', 'Seven'])
  566. def test_name(self):
  567. # Test id is used when name is not provided
  568. prop = Property()
  569. self.assertIsNotNone(prop.name)
  570. self.assertEqual(prop.name, prop.id)
  571. # Test name is properly set on init
  572. name = "rumpelstilzchen"
  573. prop = Property(name)
  574. self.assertEqual(prop.name, name)
  575. # Test name can be properly set on single and connected Properties
  576. prop = Property()
  577. self.assertNotEqual(prop.name, "prop")
  578. prop.name = "prop"
  579. self.assertEqual(prop.name, "prop")
  580. sec = Section()
  581. prop_a = Property(parent=sec)
  582. self.assertNotEqual(prop_a.name, "prop_a")
  583. prop_a.name = "prop_a"
  584. self.assertEqual(prop_a.name, "prop_a")
  585. # Test property name can be changed with siblings
  586. prop_b = Property(name="prop_b", parent=sec)
  587. self.assertEqual(prop_b.name, "prop_b")
  588. prop_b.name = "prop"
  589. self.assertEqual(prop_b.name, "prop")
  590. # Test property name set will fail on existing sibling with same name
  591. with self.assertRaises(KeyError):
  592. prop_b.name = "prop_a"
  593. self.assertEqual(prop_b.name, "prop")
  594. def test_parent(self):
  595. prop = Property("property_section", parent=Section("S"))
  596. self.assertIsInstance(prop.parent, BaseSection)
  597. self.assertEqual(len(prop.parent.props), 1)
  598. """ Test if child is removed from _props of a parent after assigning
  599. a new parent to the child """
  600. prop_parent = prop.parent
  601. prop.parent = Section("S1")
  602. self.assertEqual(len(prop_parent.props), 0)
  603. self.assertIsInstance(prop.parent, BaseSection)
  604. self.assertIsInstance(prop.parent.props[0], BaseProperty)
  605. prop_parent = prop.parent
  606. prop.parent = None
  607. self.assertIsNone(prop.parent)
  608. self.assertEqual(len(prop_parent.props), 0)
  609. with self.assertRaises(ValueError):
  610. Property("property_prop", parent=Property("P"))
  611. with self.assertRaises(ValueError):
  612. Property("property_doc", parent=Document())
  613. def test_dtype(self):
  614. prop = Property(name="prop")
  615. # Test assignment of all supported dtypes.
  616. for curr_type in DType:
  617. prop.dtype = curr_type
  618. self.assertEqual(prop.dtype, curr_type)
  619. # Test assignment of dtype alias.
  620. prop.dtype = "bool"
  621. self.assertEqual(prop.dtype, "bool")
  622. prop.dtype = "str"
  623. self.assertEqual(prop.dtype, "str")
  624. # Test assignment of tuple.
  625. prop.dtype = "2-tuple"
  626. self.assertEqual(prop.dtype, "2-tuple")
  627. # Test set None
  628. prop.dtype = None
  629. self.assertIsNone(prop.dtype)
  630. # Test assignment fails.
  631. with self.assertRaises(AttributeError):
  632. prop.dtype = 1
  633. with self.assertRaises(AttributeError):
  634. prop.dtype = "crash and burn"
  635. with self.assertRaises(AttributeError):
  636. prop.dtype = "x-tuple"
  637. # Test not setting None when a property contains values.
  638. prop.values = [1, 2, 3]
  639. self.assertIsNotNone(prop.dtype)
  640. prop.dtype = None
  641. self.assertIsNotNone(prop.dtype)
  642. def test_get_path(self):
  643. doc = Document()
  644. sec = Section(name="parent", parent=doc)
  645. # Check root path for a detached Property.
  646. prop = Property(name="prop")
  647. self.assertEqual("/", prop.get_path())
  648. # Check absolute path of Property in a Document.
  649. prop.parent = sec
  650. self.assertEqual("/%s:%s" % (sec.name, prop.name), prop.get_path())
  651. def test_id(self):
  652. prop = Property(name="P")
  653. self.assertIsNotNone(prop.id)
  654. prop = Property("P", oid="79b613eb-a256-46bf-84f6-207df465b8f7")
  655. self.assertEqual(prop.id, "79b613eb-a256-46bf-84f6-207df465b8f7")
  656. prop = Property("P", oid="id")
  657. self.assertNotEqual(prop.id, "id")
  658. # Make sure id cannot be reset programmatically.
  659. with self.assertRaises(AttributeError):
  660. prop.id = "someId"
  661. def test_new_id(self):
  662. prop = Property(name="prop")
  663. old_id = prop.id
  664. # Test assign new generated id.
  665. prop.new_id()
  666. self.assertNotEqual(old_id, prop.id)
  667. # Test assign new custom id.
  668. old_id = prop.id
  669. prop.new_id("79b613eb-a256-46bf-84f6-207df465b8f7")
  670. self.assertNotEqual(old_id, prop.id)
  671. self.assertEqual("79b613eb-a256-46bf-84f6-207df465b8f7", prop.id)
  672. # Test invalid custom id exception.
  673. with self.assertRaises(ValueError):
  674. prop.new_id("crash and burn")
  675. def test_merge_check(self):
  676. # Test dtype check
  677. source = Property(name="source", dtype="string")
  678. destination = Property(name="destination", dtype="string")
  679. destination.merge_check(source)
  680. source.dtype = "int"
  681. with self.assertRaises(ValueError):
  682. destination.merge_check(source)
  683. destination.merge_check(source, False)
  684. # Test value check
  685. source = Property(name="source", value=[1, 2, 3])
  686. destination = Property(name="destination", value=[4, 5, 6])
  687. destination.merge_check(source)
  688. # Test value convertable
  689. source = Property(name="source", value=["7", "8"])
  690. with self.assertRaises(ValueError):
  691. destination.merge_check(source)
  692. destination.merge_check(source, False)
  693. # Test value not convertable
  694. source = Property(name="source", value=["nine", "ten"])
  695. with self.assertRaises(ValueError):
  696. destination.merge_check(source)
  697. with self.assertRaises(ValueError):
  698. destination.merge_check(source, False)
  699. # Test unit check
  700. source = Property(name="source", unit="Hz")
  701. destination = Property(name="destination", unit="Hz")
  702. destination.merge_check(source)
  703. source.unit = "s"
  704. with self.assertRaises(ValueError):
  705. destination.merge_check(source)
  706. destination.merge_check(source, False)
  707. # Test uncertainty check
  708. source = Property(name="source", uncertainty=0.0)
  709. destination = Property(name="destination", uncertainty=0.0)
  710. destination.merge_check(source)
  711. source.uncertainty = 10.0
  712. with self.assertRaises(ValueError):
  713. destination.merge_check(source)
  714. destination.merge_check(source, False)
  715. # Test definition check
  716. source = Property(name="source", definition="Freude\t schoener\nGoetterfunken\n")
  717. destination = Property(name="destination",
  718. definition="FREUDE schoener GOETTERfunken")
  719. destination.merge_check(source)
  720. source.definition = "Freunde schoender Goetterfunken"
  721. with self.assertRaises(ValueError):
  722. destination.merge_check(source)
  723. destination.merge_check(source, False)
  724. # Test reference check
  725. source = Property(name="source", reference="portal.g-node.org")
  726. destination = Property(name="destination", reference="portal.g-node.org")
  727. destination.merge_check(source)
  728. source.reference = "portal.g-node.org/odml/terminologies/v1.1"
  729. with self.assertRaises(ValueError):
  730. destination.merge_check(source)
  731. destination.merge_check(source, False)
  732. # Test value origin check
  733. source = Property(name="source", value_origin="file")
  734. destination = Property(name="destination", value_origin="file")
  735. destination.merge_check(source)
  736. source.value_origin = "other file"
  737. with self.assertRaises(ValueError):
  738. destination.merge_check(source)
  739. destination.merge_check(source, False)
  740. def test_merge(self):
  741. p_dst = Property("p1", value=[1, 2, 3], unit="Hz",
  742. definition="Freude\t schoener\nGoetterfunken\n",
  743. reference="portal.g-node.org", uncertainty=0.0, value_origin="file")
  744. p_src = Property("p2", value=[2, 4, 6], unit="Hz",
  745. definition="FREUDE schoener GOETTERfunken")
  746. test_p = p_dst.clone()
  747. test_p.merge(p_src)
  748. self.assertEqual(len(test_p.values), 5)
  749. p_inv_unit = p_src.clone()
  750. p_inv_unit.unit = 's'
  751. p_inv_def = p_src.clone()
  752. p_inv_def.definition = "Freunde schoender Goetterfunken"
  753. p_inv_uncert = p_src.clone()
  754. p_inv_uncert.uncertainty = 10.0
  755. p_inv_ref = p_src.clone()
  756. p_inv_ref.reference = "test"
  757. p_inv_origin = p_src.clone()
  758. p_inv_origin.value_origin = "other file"
  759. test_p = p_dst.clone()
  760. self.assertRaises(ValueError, test_p.merge, p_inv_unit)
  761. self.assertRaises(ValueError, test_p.merge, p_inv_def)
  762. self.assertRaises(ValueError, test_p.merge, p_inv_uncert)
  763. self.assertRaises(ValueError, test_p.merge, p_inv_ref)
  764. self.assertRaises(ValueError, test_p.merge, p_inv_origin)
  765. test_p.reference = None
  766. test_p.merge(p_src)
  767. self.assertEqual(test_p.reference, p_src.reference)
  768. test_p.unit = ""
  769. test_p.merge(p_src)
  770. self.assertEqual(test_p.unit, p_src.unit)
  771. test_p.uncertainty = None
  772. test_p.merge(p_src)
  773. self.assertEqual(test_p.uncertainty, p_src.uncertainty)
  774. test_p.definition = ""
  775. test_p.merge(p_src)
  776. self.assertEqual(test_p.definition, p_src.definition)
  777. test_p.value_origin = ""
  778. test_p.merge(p_src)
  779. self.assertEqual(test_p.value_origin, p_src.value_origin)
  780. double_p = Property("adouble", value=3.14)
  781. int_p = Property("aint", value=3)
  782. self.assertRaises(ValueError, double_p.merge, int_p)
  783. int_p.merge(double_p, strict=False)
  784. self.assertEqual(len(int_p), 2)
  785. def test_clone(self):
  786. sec = Section(name="parent")
  787. # Check different id.
  788. prop = Property(name="original")
  789. clone_prop = prop.clone()
  790. self.assertNotEqual(prop.id, clone_prop.id)
  791. # Check parent removal in clone.
  792. prop.parent = sec
  793. clone_prop = prop.clone()
  794. self.assertIsNotNone(prop.parent)
  795. self.assertIsNone(clone_prop.parent)
  796. # Check keep_id
  797. prop = Property(name="keepid")
  798. clone_prop = prop.clone(True)
  799. self.assertEqual(prop.id, clone_prop.id)
  800. def test_get_merged_equivalent(self):
  801. sec = Section(name="parent")
  802. mersec = Section(name="merged_section")
  803. merprop_other = Property(name="other_prop", value="other")
  804. merprop = Property(name="prop", value=[1, 2, 3])
  805. # Check None on unset parent.
  806. prop = Property(name="prop")
  807. self.assertIsNone(prop.get_merged_equivalent())
  808. # Check None on parent without merged Section.
  809. prop.parent = sec
  810. self.assertIsNone(prop.get_merged_equivalent())
  811. # Check None on parent with merged Section but no attached Property.
  812. sec.merge(mersec)
  813. self.assertIsNone(prop.get_merged_equivalent())
  814. # Check None on parent with merged Section and unequal Property.
  815. merprop_other.parent = mersec
  816. self.assertIsNone(prop.get_merged_equivalent())
  817. # Check receiving merged equivalent Property.
  818. merprop.parent = mersec
  819. self.assertIsNotNone(prop.get_merged_equivalent())
  820. self.assertEqual(prop.get_merged_equivalent(), merprop)
  821. def test_comparison(self):
  822. p_name = "propertyName"
  823. p_origin = "from over there"
  824. p_unit = "pears"
  825. p_uncertainty = "+-12"
  826. p_ref = "4 8 15 16 23"
  827. p_def = "an odml test property"
  828. p_dep = "yes"
  829. p_dep_val = "42"
  830. p_val = ["a", "b"]
  831. prop_a = Property(name=p_name, value_origin=p_origin, unit=p_unit,
  832. uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
  833. dependency=p_dep, dependency_value=p_dep_val, value=p_val)
  834. prop_b = Property(name=p_name, value_origin=p_origin, unit=p_unit,
  835. uncertainty=p_uncertainty, reference=p_ref, definition=p_def,
  836. dependency=p_dep, dependency_value=p_dep_val, value=p_val)
  837. self.assertEqual(prop_a, prop_b)
  838. prop_b.name = 'newPropertyName'
  839. self.assertNotEqual(prop_a, prop_b)
  840. def test_export_leaf(self):
  841. doc = Document()
  842. sec_a_name = "first"
  843. sec_b_name = "second"
  844. first = doc.create_section(sec_a_name)
  845. second = first.create_section(sec_b_name)
  846. _ = first.create_section("third")
  847. prop_aa = first.create_property("prop1", value=[1.3])
  848. _ = first.create_property("prop5", value=["abc"])
  849. prop_ba = second.create_property("prop2", value=["words"])
  850. _ = second.create_property("prop3", value=["a", "b"])
  851. _ = second.create_property("prop4", value=[3])
  852. export_doc = prop_aa.export_leaf()
  853. self.assertEqual(len(export_doc[sec_a_name].properties), 2)
  854. self.assertEqual(len(export_doc[sec_a_name].sections), 0)
  855. export_doc = prop_ba.export_leaf()
  856. self.assertEqual(len(export_doc.sections), 1)
  857. self.assertEqual(len(export_doc[sec_a_name].properties), 2)
  858. self.assertEqual(len(export_doc[sec_a_name].sections), 1)
  859. self.assertEqual(len(export_doc[sec_a_name][sec_b_name].properties), 3)
  860. def test_values_cardinality(self):
  861. doc = Document()
  862. sec = Section(name="sec", type="type", parent=doc)
  863. # -- Test set cardinality on Property init
  864. # Test empty init
  865. prop_card_none = Property(name="prop_cardinality_empty", parent=sec)
  866. self.assertIsNone(prop_card_none.val_cardinality)
  867. # Test single int max init
  868. prop_card_max = Property(name="prop_cardinality_max", val_cardinality=10, parent=sec)
  869. self.assertEqual(prop_card_max.val_cardinality, (None, 10))
  870. # Test tuple init
  871. prop_card_min = Property(name="prop_cardinality_min", val_cardinality=(2, None), parent=sec)
  872. self.assertEqual(prop_card_min.val_cardinality, (2, None))
  873. # -- Test Property cardinality re-assignment
  874. prop = Property(name="prop", val_cardinality=(None, 10), parent=sec)
  875. self.assertEqual(prop.val_cardinality, (None, 10))
  876. # Test Property cardinality reset
  877. for non_val in [None, "", [], ()]:
  878. prop.val_cardinality = non_val
  879. self.assertIsNone(prop.val_cardinality)
  880. prop.val_cardinality = 1
  881. # Test Property cardinality single int max assignment
  882. prop.val_cardinality = 10
  883. self.assertEqual(prop.val_cardinality, (None, 10))
  884. # Test Property cardinality tuple max assignment
  885. prop.val_cardinality = (None, 5)
  886. self.assertEqual(prop.val_cardinality, (None, 5))
  887. # Test Property cardinality tuple min assignment
  888. prop.val_cardinality = (5, None)
  889. self.assertEqual(prop.val_cardinality, (5, None))
  890. # Test Property cardinality min/max assignment
  891. prop.val_cardinality = (1, 5)
  892. self.assertEqual(prop.val_cardinality, (1, 5))
  893. # -- Test Property cardinality assignment failures
  894. with self.assertRaises(ValueError):
  895. prop.val_cardinality = "a"
  896. with self.assertRaises(ValueError):
  897. prop.val_cardinality = -1
  898. with self.assertRaises(ValueError):
  899. prop.val_cardinality = (1, "b")
  900. with self.assertRaises(ValueError):
  901. prop.val_cardinality = (1, 2, 3)
  902. with self.assertRaises(ValueError):
  903. prop.val_cardinality = (-1, 1)
  904. with self.assertRaises(ValueError):
  905. prop.val_cardinality = (1, -5)
  906. with self.assertRaises(ValueError):
  907. prop.val_cardinality = (5, 1)
  908. def test_set_values_cardinality(self):
  909. doc = Document()
  910. sec = Section(name="sec", type="sec_type", parent=doc)
  911. prop = Property(name="prop", val_cardinality=1, parent=sec)
  912. # Test Property values cardinality min assignment
  913. prop.set_values_cardinality(1)
  914. self.assertEqual(prop.val_cardinality, (1, None))
  915. # Test Property values cardinality keyword min assignment
  916. prop.set_values_cardinality(min_val=2)
  917. self.assertEqual(prop.val_cardinality, (2, None))
  918. # Test Property values cardinality max assignment
  919. prop.set_values_cardinality(None, 1)
  920. self.assertEqual(prop.val_cardinality, (None, 1))
  921. # Test Property values cardinality keyword max assignment
  922. prop.set_values_cardinality(max_val=2)
  923. self.assertEqual(prop.val_cardinality, (None, 2))
  924. # Test Property values cardinality min max assignment
  925. prop.set_values_cardinality(1, 2)
  926. self.assertEqual(prop.val_cardinality, (1, 2))
  927. # Test Property values cardinality keyword min max assignment
  928. prop.set_values_cardinality(min_val=2, max_val=5)
  929. self.assertEqual(prop.val_cardinality, (2, 5))
  930. # Test Property values cardinality empty reset
  931. prop.set_values_cardinality()
  932. self.assertIsNone(prop.val_cardinality)
  933. # Test Property values cardinality keyword empty reset
  934. prop.set_values_cardinality(1)
  935. self.assertIsNotNone(prop.val_cardinality)
  936. prop.set_values_cardinality(min_val=None, max_val=None)
  937. self.assertIsNone(prop.val_cardinality)