test_relations.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. from unittest import mock
  2. from iepy.data.models import EvidenceLabel
  3. from .factories import (
  4. RelationFactory, EntityFactory, EntityKindFactory,
  5. TextSegmentFactory, EntityOccurrenceFactory,
  6. IEDocFactory,
  7. )
  8. from .manager_case import ManagerTestCase
  9. class TestRelations(ManagerTestCase):
  10. def test_cant_change_kinds_after_creation(self):
  11. r = RelationFactory()
  12. new_ek = EntityKindFactory()
  13. r.left_entity_kind = new_ek
  14. self.assertRaises(ValueError, r.save)
  15. class BaseTestReferenceBuilding(ManagerTestCase):
  16. # Reference = a complete labeled Corpus
  17. def setUp(self):
  18. self.k_person = EntityKindFactory(name='person')
  19. self.k_location = EntityKindFactory(name='location')
  20. self.k_org = EntityKindFactory(name='organization')
  21. self.john = EntityFactory(key='john', kind=self.k_person)
  22. self.peter = EntityFactory(key='peter', kind=self.k_person)
  23. self.london = EntityFactory(key='london', kind=self.k_location)
  24. self.roma = EntityFactory(key='roma', kind=self.k_location)
  25. self.UN = EntityFactory(key='United Nations', kind=self.k_org)
  26. self.WHO = EntityFactory(key='World Health Organization', kind=self.k_org)
  27. self.r_lives_in = RelationFactory(left_entity_kind=self.k_person,
  28. right_entity_kind=self.k_location)
  29. self.r_was_born_in = RelationFactory(left_entity_kind=self.k_person,
  30. right_entity_kind=self.k_location)
  31. self.r_father_of = RelationFactory(left_entity_kind=self.k_person,
  32. right_entity_kind=self.k_person)
  33. self.weak_label = EvidenceLabel.SKIP # means that will need to be re-labeled
  34. self.solid_label = EvidenceLabel.YESRELATION
  35. def create_occurrence(self, doc, e, offset, end):
  36. return EntityOccurrenceFactory(document=doc, entity=e,
  37. offset=offset, offset_end=end)
  38. def segment_with_occurrences_factory(self, occurrences=tuple(), **kwargs):
  39. s = TextSegmentFactory(**kwargs)
  40. for occurrence_data in occurrences:
  41. if isinstance(occurrence_data, (list, tuple)):
  42. e, start, end = occurrence_data
  43. else:
  44. e = occurrence_data
  45. start, end = 0, 1 # just something, the simplest
  46. eo = self.create_occurrence(s.document, e, start, end)
  47. s.entity_occurrences.add(eo)
  48. return s
  49. class TestReferenceNextSegmentToLabel(BaseTestReferenceBuilding):
  50. judge = "iepy"
  51. # the method to test, shorcut
  52. def next(self, relation=None, **kwargs):
  53. if relation is None:
  54. relation = self.r_lives_in
  55. if 'judge' not in kwargs:
  56. kwargs['judge'] = self.judge
  57. return relation.get_next_segment_to_label(**kwargs)
  58. def test_if_no_segment_around_None_is_returned(self):
  59. self.assertIsNone(self.next())
  60. def test_if_segments_exists_but_with_no_matching_occurrences_None(self):
  61. self.segment_with_occurrences_factory() # No occurrences at all
  62. self.assertIsNone(self.next())
  63. self.segment_with_occurrences_factory([self.john])
  64. self.segment_with_occurrences_factory([self.roma])
  65. self.assertIsNone(self.next())
  66. self.segment_with_occurrences_factory([self.john, self.WHO])
  67. self.segment_with_occurrences_factory([self.roma, self.WHO])
  68. self.assertIsNone(self.next())
  69. self.segment_with_occurrences_factory([self.john, self.peter])
  70. self.segment_with_occurrences_factory([self.roma, self.london])
  71. self.assertIsNone(self.next())
  72. def test_if_matching_kinds_is_retrieved(self):
  73. s = self.segment_with_occurrences_factory([self.john, self.roma])
  74. self.assertEqual(s, self.next())
  75. def test_if_segment_has_several_of_the_matching_kinds_is_still_found(self):
  76. s = self.segment_with_occurrences_factory([self.john, self.peter, self.roma])
  77. self.assertEqual(s, self.next())
  78. def test_if_segment_has_matching_and_other_kinds_is_still_found(self):
  79. s = self.segment_with_occurrences_factory([self.john, self.roma, self.UN])
  80. self.assertEqual(s, self.next())
  81. def test_segment_with_lowest_id_is_retrieved(self):
  82. s1 = self.segment_with_occurrences_factory([self.john, self.roma])
  83. self.segment_with_occurrences_factory([self.peter, self.london])
  84. self.assertEqual(s1, self.next())
  85. def test_relation_of_same_kind_expect_at_least_2_of_them(self):
  86. self.segment_with_occurrences_factory([self.john])
  87. self.segment_with_occurrences_factory([self.peter, self.london, self.WHO])
  88. self.assertIsNone(self.next(relation=self.r_father_of))
  89. s = self.segment_with_occurrences_factory([self.john, self.peter])
  90. self.assertEqual(s, self.next(relation=self.r_father_of))
  91. def test_relation_of_same_kind_accepts_2_occurrences_of_same_entity(self):
  92. s = self.segment_with_occurrences_factory([self.john, (self.john, 2, 3)])
  93. self.assertEqual(s, self.next(relation=self.r_father_of))
  94. # until now, only Entity Kind matching. Let's check about existence and properties
  95. # of questions - aka Labeled-Evidence
  96. def test_if_segment_has_all_questions_answered_is_omitted(self):
  97. s = self.segment_with_occurrences_factory([self.john, self.london])
  98. self.assertIsNotNone(self.next())
  99. for evidence in s.get_evidences_for_relation(self.r_lives_in):
  100. evidence.set_label(self.r_lives_in, self.solid_label, self.judge)
  101. self.assertIsNone(self.next())
  102. def test_if_segment_has_all_questions_answered_for_other_relation_is_NOT_omitted(self):
  103. s = self.segment_with_occurrences_factory([self.john, self.london])
  104. self.assertIsNotNone(self.next())
  105. for evidence in s.get_evidences_for_relation(self.r_was_born_in):
  106. evidence.set_label(self.r_was_born_in, self.solid_label, self.judge)
  107. self.assertEqual(s, self.next())
  108. def test_if_segment_has_question_not_labeled_is_found(self):
  109. s = self.segment_with_occurrences_factory([self.john, self.london])
  110. self.assertIsNotNone(self.next())
  111. for evidence in s.get_evidences_for_relation(self.r_lives_in):
  112. evidence_label = evidence.labels.filter(judge=self.judge)
  113. evidence_label.delete()
  114. self.assertEqual(s, self.next())
  115. def test_if_segment_has_question_with_label_None_is_found_by_same_judge(self):
  116. s = self.segment_with_occurrences_factory([self.john, self.london])
  117. s_2 = self.segment_with_occurrences_factory([self.john, self.roma])
  118. self.assertIsNotNone(self.next())
  119. for evidence in s.get_evidences_for_relation(self.r_lives_in):
  120. evidence.labels.all().delete() # just to be sure, but shall be empty
  121. evidence.set_label(self.r_lives_in, None, self.judge)
  122. self.assertEqual(s, self.next())
  123. # Now, for other judge, that segment is put last
  124. other_judge = 'someone else'
  125. self.assertEqual(s_2, self.next(judge=other_judge))
  126. # But still foundable if it's the last one available
  127. s_2.delete()
  128. self.assertEqual(s, self.next(judge=other_judge))
  129. def test_if_segment_has_question_labeled_with_dont_know_is_found(self):
  130. s = self.segment_with_occurrences_factory([self.john, self.london])
  131. self.assertIsNotNone(self.next())
  132. for evidence in s.get_evidences_for_relation(self.r_lives_in):
  133. evidence.set_label(self.r_lives_in, self.weak_label, self.judge)
  134. self.assertEqual(s, self.next())
  135. def test_if_segment_was_fully_labeled_but_some_empty_for_other_relation_is_omitted(self):
  136. # ie, LabeledE Evidences of a Segment with some other relation doesnt matter here.
  137. # This test is more for ensuring we are not coding an underised side-effect
  138. s = self.segment_with_occurrences_factory([self.john, self.london])
  139. for evidence in s.get_evidences_for_relation(self.r_lives_in):
  140. evidence.set_label(self.r_lives_in, self.solid_label, self.judge)
  141. self.assertIsNone(self.next())
  142. def test_if_segment_has_some_questions_answered_but_other_dont_know_is_found(self):
  143. s = self.segment_with_occurrences_factory([self.john, self.peter, self.london])
  144. self.assertIsNotNone(self.next())
  145. for evidence, lbl in zip(s.get_evidences_for_relation(self.r_lives_in),
  146. [self.weak_label, self.solid_label]):
  147. evidence.set_label(self.r_lives_in, lbl, self.judge)
  148. self.assertEqual(s, self.next())
  149. def test_if_segment_was_fully_labeled_but_some_dunno_for_other_relation_is_omitted(self):
  150. # ie, LabeledE Evidences of a Segment with some other relation doesnt matter here.
  151. # This test is more for ensuring we are not coding an underised side-effect
  152. s = self.segment_with_occurrences_factory([self.john, self.london])
  153. for evidence in s.get_evidences_for_relation(self.r_lives_in):
  154. evidence.set_label(self.r_lives_in, self.solid_label, self.judge)
  155. for evidence in s.get_evidences_for_relation(self.r_was_born_in):
  156. evidence.set_label(self.r_was_born_in, self.weak_label, self.judge)
  157. self.assertIsNone(self.next())
  158. def test_segments_with_zero_evidence_labeled_are_prefered(self):
  159. s = self.segment_with_occurrences_factory([self.john, self.london])
  160. for evidence in s.get_evidences_for_relation(self.r_lives_in):
  161. evidence.set_label(self.r_lives_in, self.weak_label, self.judge)
  162. # so, this segment is found when searching...
  163. self.assertEqual(s, self.next())
  164. # But if a new one appears, pristine, with no evidences, is preferred
  165. s2 = self.segment_with_occurrences_factory([self.peter, self.london])
  166. self.assertEqual(s2, self.next())
  167. def test_matching_text_segments_no_duplicates_no_extra(self):
  168. a = self.segment_with_occurrences_factory([self.john, self.peter, self.london, self.roma])
  169. b = self.segment_with_occurrences_factory([self.john, self.peter, self.london])
  170. c = self.segment_with_occurrences_factory([self.john, self.london])
  171. self.segment_with_occurrences_factory([self.roma, self.london])
  172. real = list(self.r_lives_in._matching_text_segments())
  173. expected = set([a, b, c])
  174. self.assertEqual(len(real), len(expected))
  175. self.assertEqual(set(real), expected)
  176. class TestNavigateLabeledSegments(BaseTestReferenceBuilding):
  177. judge = "iepy"
  178. def create_labeled_segments_for_relation(self, relation, how_many):
  179. result = []
  180. for i in range(how_many):
  181. s = self.segment_with_occurrences_factory([self.john, self.london, self.roma])
  182. result.append(s)
  183. for le in s.get_evidences_for_relation(relation):
  184. le.set_label(relation, self.solid_label, self.judge)
  185. return result
  186. def test_asking_neighbor_when_nothing_is_labeled_returns_None(self):
  187. segm = TextSegmentFactory()
  188. self.assertIsNone(self.r_lives_in.labeled_neighbor(segm, self.judge))
  189. def test_labeled_evidences_for_other_relations_doesnt_affect(self):
  190. segm = TextSegmentFactory()
  191. self.create_labeled_segments_for_relation(self.r_father_of, 5)
  192. self.assertIsNone(self.r_lives_in.labeled_neighbor(segm, self.judge))
  193. def test_asking_previous_returns_low_closest_segment_with_labeled_evidences(self):
  194. r = self.r_lives_in
  195. segments = self.create_labeled_segments_for_relation(r, 5)
  196. reference = segments[2] # the one in the middle
  197. prev_id = r.labeled_neighbor(reference, self.judge, back=True)
  198. self.assertEqual(prev_id, segments[1].id)
  199. # But if that had no labeled evidences...
  200. segments[1].evidence_relations.all().delete()
  201. prev_id = r.labeled_neighbor(reference, self.judge, back=True)
  202. self.assertEqual(prev_id, segments[0].id)
  203. def test_segments_with_all_empty_answers_are_excluded(self):
  204. # Because they have zero actual labels
  205. r = self.r_lives_in
  206. segments = self.create_labeled_segments_for_relation(r, 5)
  207. reference = segments[2] # the one in the middle
  208. seg_1_evidences = list(segments[1].get_evidences_for_relation(r))
  209. assert len(seg_1_evidences) > 1
  210. seg_1_evidences[0].set_label(r, None, judge=self.judge)
  211. # some none, not all, still found
  212. self.assertEqual(
  213. segments[1].id,
  214. r.labeled_neighbor(reference, self.judge, back=True)
  215. )
  216. for le in seg_1_evidences:
  217. le.set_label(r, None, judge=self.judge)
  218. # all none, not found
  219. self.assertNotEqual(
  220. segments[1].id,
  221. r.labeled_neighbor(reference, self.judge, back=True)
  222. )
  223. self.assertEqual(segments[0].id,
  224. r.labeled_neighbor(reference, self.judge, back=True))
  225. def test_all_labels_empty_for_this_relation_but_filled_for_other_still_omitted(self):
  226. r = self.r_lives_in
  227. segments = self.create_labeled_segments_for_relation(r, 5)
  228. reference = segments[2] # the one in the middle
  229. for le in segments[1].get_evidences_for_relation(r):
  230. le.set_label(r, None, judge=self.judge)
  231. # all none for relation "r_lives_in", shall be not found
  232. for le in segments[1].get_evidences_for_relation(self.r_father_of):
  233. le.set_label(r, self.solid_label, self.judge)
  234. self.assertNotEqual(
  235. segments[1].id,
  236. r.labeled_neighbor(reference, self.judge, back=True)
  237. )
  238. def test_asking_next_returns_high_closest_segment_with_labeled_evidences(self):
  239. r = self.r_lives_in
  240. segments = self.create_labeled_segments_for_relation(r, 5)
  241. reference = segments[2] # the one in the middle
  242. next_id = r.labeled_neighbor(reference, self.judge, back=False)
  243. self.assertEqual(next_id, segments[3].id)
  244. # But if that had no labeled evidences...
  245. segments[3].evidence_relations.all().delete()
  246. next_id = r.labeled_neighbor(reference, self.judge, back=False)
  247. self.assertEqual(next_id, segments[4].id)
  248. def test_asking_for_neighbor_of_unlabeled_segment_returns_last_available(self):
  249. r = self.r_lives_in
  250. segments = self.create_labeled_segments_for_relation(r, 5)
  251. s = self.segment_with_occurrences_factory()
  252. expected = segments[-1].id
  253. self.assertEqual(expected, r.labeled_neighbor(s, self.judge, back=True))
  254. self.assertEqual(expected, r.labeled_neighbor(s, self.judge, back=False))
  255. def test_delete_a_label_is_the_same_as_settings_as_none(self):
  256. r = self.r_lives_in
  257. segments = self.create_labeled_segments_for_relation(r, 5)
  258. reference = segments[2] # the one in the middle
  259. seg_1_evidences = list(segments[1].get_evidences_for_relation(r))
  260. assert len(seg_1_evidences) > 1
  261. label_obj = seg_1_evidences[0].labels.get(judge=self.judge)
  262. label_obj.delete()
  263. # deleted just one, not all, still found
  264. self.assertEqual(
  265. segments[1].id,
  266. r.labeled_neighbor(reference, self.judge, back=True)
  267. )
  268. for le in seg_1_evidences[1:]:
  269. label_obj = le.labels.get(judge=self.judge)
  270. label_obj.delete()
  271. # delete all, not found
  272. self.assertNotEqual(
  273. segments[1].id,
  274. r.labeled_neighbor(reference, self.judge, back=True)
  275. )
  276. self.assertEqual(
  277. segments[0].id,
  278. r.labeled_neighbor(reference, self.judge, back=True)
  279. )
  280. class TestNavigateLabeledDocuments(BaseTestReferenceBuilding):
  281. judge = "iepy"
  282. def create_labeled_documents_for_relation(self, relation, how_many):
  283. result = []
  284. for i in range(how_many):
  285. s = self.segment_with_occurrences_factory(
  286. [self.john, self.london, self.roma],
  287. document=IEDocFactory()
  288. )
  289. result.append(s)
  290. for le in s.get_evidences_for_relation(relation):
  291. le.set_label(relation, self.solid_label, self.judge)
  292. return list(set([x.document for x in result]))
  293. def test_asking_previous_returns_low_closest_document_with_labeled_evidences(self):
  294. r = self.r_lives_in
  295. documents = self.create_labeled_documents_for_relation(r, 5)
  296. reference = documents[2] # the one in the middle
  297. prev_id = r.labeled_neighbor(reference, self.judge, back=True)
  298. self.assertEqual(prev_id, documents[1].id)
  299. # But if that had no labeled evidences...
  300. for segment in documents[1].segments.all():
  301. segment.evidence_relations.all().delete()
  302. prev_id = r.labeled_neighbor(reference, self.judge, back=True)
  303. self.assertEqual(prev_id, documents[0].id)
  304. class TestReferenceNextDocumentToLabel(BaseTestReferenceBuilding):
  305. judge = 'someone'
  306. def setUp(self):
  307. super().setUp()
  308. self.relation = self.r_lives_in
  309. self.eo1, self.eo2 = self.john, self.roma
  310. patcher = mock.patch.object(self.relation, 'get_next_segment_to_label')
  311. self.mock_next_segment = patcher.start()
  312. self.addCleanup(patcher.stop)
  313. self.mock_next_segment.return_value = None
  314. def test_if_no_segment_returned_then_no_document_returned(self):
  315. self.assertEqual(self.relation.get_next_document_to_label(self.judge), None)
  316. self.mock_next_segment.assert_called_once_with(self.judge)
  317. def test_if_segment_returned_then_its_document_is_returned(self):
  318. s = self.segment_with_occurrences_factory([self.eo1, self.eo2])
  319. self.mock_next_segment.return_value = s
  320. self.assertEqual(self.relation.get_next_document_to_label(self.judge), s.document)
  321. self.mock_next_segment.assert_called_once_with(self.judge)