def test_segments_only_trees(): """Files without a single root must get a virtual one.""" # minimal case: file without any segments produced = example2tree("empty.rs3") expected = t("", []) assert produced.edu_strings == produced.tree.leaves() == [] assert expected == produced.tree # one segment only produced = example2tree('only-one-segment.rs3') expected = t("N", ["foo"]) assert produced.edu_strings == produced.tree.leaves() == ['foo'] assert expected == produced.tree # two segments w/out a root produced = example2tree("foo-bar-only-segments.rs3") expected = t(VIRTUAL_ROOT, [("N", ["foo"]), ("N", ["bar"])]) assert produced.edu_strings == produced.tree.leaves() == ['foo', 'bar'] assert expected == produced.tree # three segments w/out a root produced = example2tree('eins-zwei-drei-only-segments.rs3') expected = t(VIRTUAL_ROOT, [("N", ["eins"]), ("N", ["zwei"]), ("N", ["drei"])]) assert produced.edu_strings == produced.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert expected == produced.tree
def test_fix_rs3filewriter_newlines_in_edus(): """An RST tree that contains newlines in its EDUs can be converted into an rs3 file just like a tree without newlines.""" t_good = t('Temporal', [('N', ['Szeryng subsequently focused on teaching']), ('S', ['before resuming his concert career in 1954.'])]) t_bad = t('Temporal', [('N', ['Szeryng\nsubsequently\nfocused on\nteaching']), ('S', ['before resuming\nhis concert\ncareer in 1954.'])]) tempfile = NamedTemporaryFile() RS3FileWriter(t_good, output_filepath=tempfile.name) produced_good_output_tree = RSTTree(tempfile.name) tempfile = NamedTemporaryFile() RS3FileWriter(t_bad, output_filepath=tempfile.name) produced_bad_output_tree = RSTTree(tempfile.name) assert produced_good_output_tree.edu_strings == \ produced_bad_output_tree.edu_strings assert produced_good_output_tree.tree == \ produced_bad_output_tree.tree
def convert_schema(self, nuc_tuple, inner_sat_tuples, outer_sat_tuples): """subtrees are represented as (tree, linear tree position) tuples. returns relation as root node. """ nuc_tree, nuc_pos = nuc_tuple sat_tuples = inner_sat_tuples + outer_sat_tuples last_sat_tuple_pos = len(sat_tuples) - 1 for i, (sat_tree, sat_pos) in enumerate(sat_tuples): relname = self.get_relname(sat_tree.root_id) if sat_pos < nuc_pos: ordered_trees = [sat_tree, nuc_tree] else: ordered_trees = [nuc_tree, sat_tree] if i == last_sat_tuple_pos: nuc_tree = t(relname, ordered_trees, debug=self.debug, root_id=nuc_tree.root_id) else: nuc_tree = t('N', [(relname, ordered_trees)], debug=self.debug, root_id=nuc_tree.root_id) return nuc_tree
def root2tree(self, start_node=None): root_nodes = self.child_dict[start_node] num_roots = len(root_nodes) if num_roots == 1: return self.dt(start_node=root_nodes[0]) elif num_roots > 1: # An undesired, but common case (at least in the PCC corpus). # This happens if there's one EDU not to connected to the rest # of the tree (e.g. a headline). We will just make all 'root' # nodes part of a multinuc relation called VIRTUAL_ROOT. logging.log( logging.INFO, "File '{}' has {} roots!".format( os.path.basename(self.filepath), num_roots)) root_subtrees = [ n_wrap(self.dt(start_node=root_id), debug=self.debug, root_id=root_id) for root_id in root_nodes ] sorted_subtrees = self.sort_subtrees(*root_subtrees) # assign the root_id of the highest subtree to the virtual root max_height, virtual_root_id = max( (st.height(), st.root_id) for st in sorted_subtrees) return t(VIRTUAL_ROOT, sorted_subtrees, debug=self.debug, root_id=virtual_root_id) else: return t('')
def make_span(parented_tree): """create a 'span' or 'leaf' subtree for dis/lisp/RST-DT-formatted trees. Examples: span (a subtree that covers the leaves 1 to 7) ___|____ 1 7 leaf (a subtree that only covers leaf 7) | 7 """ all_leaves = all_leaf_positions(parented_tree) if is_root(parented_tree): return t('span', ['1', str(len(all_leaves))]) subtree_leaves = subtree_leaf_positions(parented_tree) if len(subtree_leaves) == 1: edu_id = all_leaves.index(subtree_leaves[0]) + 1 return t('leaf', [str(edu_id)]) elif len(subtree_leaves) > 1: first_edu_id = all_leaves.index(subtree_leaves[0]) + 1 last_edu_id = all_leaves.index(subtree_leaves[-1]) + 1 return t('span', [str(first_edu_id), str(last_edu_id)]) else: raise NotImplementedError('Subtree has no leaves')
def test_pcc_3367(): produced = example2tree('maz-3367-excerpt.rs3', rs3tree_dir=RS3TREE_DIR) list_2_7 = ('list', [ ('N', ['2']), ('N', ['3']), ('N', ['4']), ('N', ['5']), ('N', ['6']), ('N', ['7']), ]) evidence_2_9 = ('evidence', [('S', [list_2_7]), ('N', [('concession', [ ('S', ['8']), ('N', ['9']), ])])]) interpretation_2_12 = ('interpretation', [ ('S', [evidence_2_9]), ('N', [('evaluation-s', [('N', ['10']), ('S', [('conjunction', [('N', ['11']), ('N', ['12'])])])])]) ]) eval_13_14 = ('evaluation-n', [('S', ['13']), ('N', ['14'])]) anti_15_16 = ('antithesis', [('S', ['15']), ('N', ['16'])]) list_15_17 = t('list', [('N', [anti_15_16]), ('N', ['17'])]) cond_18_19 = ('condition', [('S', ['18']), ('N', ['19'])]) reason_20_23 = ('reason', [('S', ['20']), ('N', [('reason', [ ('N', ['21']), ('S', [('conjunction', [('N', ['22']), ('N', ['23'])])]) ])])]) inner_tree_18_23 = ('evidence', [('N', [cond_18_19]), ('S', [reason_20_23])]) second_tree_15_23 = ('evidence', [('S', [list_15_17]), ('N', [inner_tree_18_23])]) third_tree_13_23 = ('evidence', [('S', [eval_13_14]), ('N', [second_tree_15_23])]) background_2_23 = ('background', [('S', [interpretation_2_12]), ('N', [third_tree_13_23])]) expected = t(VIRTUAL_ROOT, [('N', ['1']), ('N', [background_2_23])]) assert produced.edu_strings == produced.tree.leaves() == [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23' ] assert expected == produced.tree
def test_nested_nucsat_multinuc_relation(): produced = example2tree( 'eins-zwei-drei-(circ-eins-to-(joint-zwei-and-drei).rs3') expected = t("circumstance", [("S", ["eins"]), ("N", [("joint", [("N", ["zwei"]), ("N", ["drei"])])])]) assert produced.edu_strings == produced.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert expected == produced.tree produced = example2tree( 'eins-zwei-drei-(circ-(joint-eins-and-zwei)-from-drei).rs3') expected = t("circumstance", [("N", [("joint", [("N", ["eins"]), ("N", ["zwei"])])]), ("S", ["drei"])]) assert produced.edu_strings == produced.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert expected == produced.tree produced = example2tree( 'eins-zwei-drei-(circ-eins-from-(joint-zwei-and-drei).rs3') expected = t("circumstance", [("N", ["eins"]), ("S", [("joint", [("N", ["zwei"]), ("N", ["drei"])])])]) assert produced.edu_strings == produced.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert expected == produced.tree produced = example2tree( 'eins-zwei-drei-(circ-(joint-eins-and-zwei)-to-drei).rs3') expected = t("circumstance", [("S", [("joint", [("N", ["eins"]), ("N", ["zwei"])])]), ("N", ["drei"])]) assert produced.edu_strings == produced.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert expected == produced.tree produced = example2tree( 'eins-zwei-drei-(elab-eins-from-(joint-zwei-and-drei).rs3') expected = t('elaboration', [("N", ["eins"]), ("S", [("joint", [("N", ["zwei"]), ("N", ["drei"])])])]) assert produced.edu_strings == produced.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert expected == produced.tree
def gen_numbered_nucsat(first_element, number): expected_elems = ('N', 'S') assert first_element in expected_elems nuc = ('N', ['nuc']) sat = ('S', ['sat-{}'.format(number)]) if first_element == 'N': return t('nuc-sat-{}'.format(number), [nuc, sat]) else: return t('sat-nuc-{}'.format(number), [sat, nuc])
def test_no_span_nodes(): """The no_span_nodes test function works as expected.""" good_tree = t('joint', [ ('N', ['foo']), ('N', [('background', [('S', ['bar']), ('N', ['baz'])])]), ]) bad_tree = t('joint', [ ('N', ['foo']), ('N', [('span', [('S', ['bar']), ('N', ['baz'])])]), ]) assert no_span_nodes(good_tree) is True assert no_span_nodes(bad_tree) is False
def test_no_double_ns(): """The test function no_double_ns() works as expected.""" bad_tree = t('N', [('S', ['foo']), ('N', ['bar'])]) bad_embedded_tree = t('joint', [ ('N', [('N', ['foo'])]), ('N', ['bar']), ]) good_tree = t('elabortate', [('S', ['foo']), ('N', ['bar'])]) assert no_double_ns(bad_tree, "testfile") == False assert no_double_ns(bad_embedded_tree, "testfile") == False assert no_double_ns(good_tree, "testfile") == True
def sorted_nucsat_tree(self, nuc_tree, sat_tree): sorted_subtrees = self.sort_subtrees(nuc_tree, sat_tree) relname = self.get_relname(sat_tree.root_id) return t(relname, sorted_subtrees, debug=self.debug, root_id=nuc_tree.root_id)
def test_nucsat(): """A single nucleus-satellite relation is converted into rst.sty format.""" sat_before_nuc = \ t('circumstance', [ ('S', ['sat first']), ('N', ['nuc second']) ]) result = rstc.write_rstlatex(sat_before_nuc) assert result.rstlatextree == '\\dirrel\n\t{circumstance}{\\rstsegment{sat first}}\n\t{}{\\rstsegment{nuc second}}' nuc_before_sat = \ t('circumstance', [ ('N', ['nuc first']), ('S', ['sat second']) ]) result = rstc.write_rstlatex(nuc_before_sat) assert result.rstlatextree == '\\dirrel\n\t{}{\\rstsegment{nuc first}}\n\t{circumstance}{\\rstsegment{sat second}}'
def test_single_nucsat_relation_topspan(): """It doesn't matter if there is a span above a single N-S relation.""" produced1 = example2tree("foo-bar-circ-foo-to-bar-plus-top-span.rs3") produced2 = example2tree("foo-bar-circ-foo-to-bar.rs3") expected = t("circumstance", [("S", ["foo"]), ("N", ["bar"])]) assert produced1.edu_strings == produced1.tree.leaves() == ['foo', 'bar'] assert produced2.edu_strings == produced2.tree.leaves() == ['foo', 'bar'] assert expected == produced1.tree == produced2.tree
def test_single_multinuc_relation_topspan(): """It doesn't matter if there is a span above a single multinuc relation.""" produced1 = example2tree("foo-bar-foo-joint-bar.rs3") produced2 = example2tree("foo-bar-foo-joint-bar-plus-top-span.rs3") expected = t("joint", [("N", ["foo"]), ("N", ["bar"])]) assert produced1.edu_strings == produced1.tree.leaves() == ['foo', 'bar'] assert produced2.edu_strings == produced2.tree.leaves() == ['foo', 'bar'] assert expected == produced1.tree == produced2.tree
def convert(parented_tree): if is_root(parented_tree): span_description = make_span(parented_tree) children = [span_description] for subtree in get_nucsat_subtrees(parented_tree): children.append(convert(subtree)) orphaned_children = [orphanize(child) for child in children] return t('Root', orphaned_children) elif is_leaf(parented_tree): return make_edu(parented_tree) else: span_description = make_span(parented_tree) rel_description = make_rel2par(parented_tree) children = [span_description, rel_description] for subtree in get_nucsat_subtrees(parented_tree): children.append(convert(subtree)) tree_label = convert_label(parented_tree.label()) orphaned_children = [orphanize(child) for child in children] return t(tree_label, orphaned_children)
def test_read_dplp_one_edu(fixtures_input_dir): input_file = os.path.join(fixtures_input_dir, 'one-edu.dplp') input_tree = rstc.read_dplp(input_file) tempfile = NamedTemporaryFile() rstc.write_rs3(input_tree, tempfile.name) produced_output_tree = rstc.read_rs3tree(tempfile.name) assert input_tree.tree == produced_output_tree.tree == t( 'N', ['good food .'])
def test_multinuc(): """A multinuclear relation is converted into rst.sty format.""" contrast = \ t('contrast', [ ('N', ['nuc-1']), ('N', ['nuc-2']) ]) result = rstc.write_rstlatex(contrast) assert result.rstlatextree == '\\multirel{contrast}\n\t{\\rstsegment{nuc-1}}\n\t{\\rstsegment{nuc-2}}' joint = \ t('joint', [ ('N', ['nuc-1']), ('N', ['nuc-2']), ('N', ['nuc-3']) ]) result = rstc.write_rstlatex(joint) assert result.rstlatextree == '\\multirel{joint}\n\t{\\rstsegment{nuc-1}}\n\t{\\rstsegment{nuc-2}}\n\t{\\rstsegment{nuc-3}}'
def test_isanlp_tree(): """ This is a weird edge case produced by the isanlp_rst parser, basically a multinuc relation in a <group ... type="span"/> instead of a <group ... type="multinuc" />. RSTTool accepts this, we should too. """ produced = example2tree("isanlp_rst1.rs3") expected = t("joint", [("N", ['foo']), ("N", ['bar'])]) assert produced.edu_strings == produced.tree.leaves() == ['foo', 'bar'] assert expected == produced.tree
def test_single_multinuc_relation(): produced = example2tree("foo-bar-foo-joint-bar.rs3") expected = t("joint", [("N", ["foo"]), ("N", ["bar"])]) assert produced.edu_strings == produced.tree.leaves() == ['foo', 'bar'] assert expected == produced.tree produced = example2tree("foo-bar-foo-conj-bar.rs3") expected = t("conjunction", [("N", ["foo"]), ("N", ["bar"])]) assert produced.edu_strings == produced.tree.leaves() == ['foo', 'bar'] assert expected == produced.tree produced = example2tree( 'eins-zwei-drei-(joint-eins-and-zwei-and-drei).rs3') expected = t("joint", [("N", ["eins"]), ("N", ["zwei"]), ("N", ["drei"])]) assert produced.edu_strings == produced.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert expected == produced.tree
def test_rs3filewriter_onesegmenttree(): """A DGParentedTree with only one segment is correctly converted into an RS3 file and back.""" input_tree = t("N", ["foo"]) expected_output_tree = example2tree('only-one-segment.rs3') tempfile = NamedTemporaryFile() RS3FileWriter(input_tree, output_filepath=tempfile.name) produced_output_tree = RSTTree(tempfile.name) assert produced_output_tree.edu_strings == produced_output_tree.tree.leaves( ) == ['foo'] assert input_tree == expected_output_tree.tree == produced_output_tree.tree
def test_rs3filewriter_emptytree(): """An empty DGParentedTree is converted into an empty RS3 file and back.""" input_tree = t("", []) expected_output_tree = example2tree("empty.rs3") tempfile = NamedTemporaryFile() RS3FileWriter(input_tree, output_filepath=tempfile.name) produced_output_tree = RSTTree(tempfile.name) assert produced_output_tree.edu_strings == produced_output_tree.tree.leaves( ) == [] assert input_tree == expected_output_tree.tree == produced_output_tree.tree
def test_pcc_00001(): # original error: A multinuc segment (18) should not have children: ['40'] # WARNING:root:File maz-00001.rs3: Node 'conjunction' has child 'condition' produced = example2tree('maz-00001-excerpt.rs3', rs3tree_dir=RS3TREE_DIR) con_4_5 = ('conjunction', [n(['4']), n(['5'])]) cause_3_5 = ('cause', [s(['3']), n([con_4_5])]) cause_6_7 = ('cause', [n(['6']), s(['7'])]) inter_3_7 = ('interpretation', [n([cause_3_5]), s([cause_6_7])]) inter_2_7 = ('interpretation', [s(['2']), n([inter_3_7])]) eval_2_8 = ('evaluation-n', [s([inter_2_7]), n(['8'])]) cond_13_14 = ('condition', [n(['13']), s(['14'])]) conj_12_14 = ('conjunction', [n(['12']), n([cond_13_14])]) evidence_11_14 = ('evidence', [n(['11']), s([conj_12_14])]) reason_10_14 = ('reason', [n(['10']), s([evidence_11_14])]) list_9_14 = ('list', [n(['9']), n([reason_10_14])]) reason_2_14 = ('reason', [n([eval_2_8]), s([list_9_14])]) reason_17_18 = ('reason', [n(['17']), s(['18'])]) conj_16_18 = ('conjunction', [n(['16']), n([reason_17_18])]) reason_15_18 = ('reason', [n(['15']), s([conj_16_18])]) elab_19_20 = ('elaboration', [n(['19']), s(['20'])]) dis_21_22 = ('disjunction', [n(['21']), n(['22'])]) inter_19_22 = ('interpretation', [s([elab_19_20]), n([dis_21_22])]) result_15_22 = ('result', [n([reason_15_18]), s([inter_19_22])]) joint_2_22 = ('joint', [n([reason_2_14]), n([result_15_22])]) expected = t(VIRTUAL_ROOT, [n(['1']), n([joint_2_22])]) assert produced.edu_strings == produced.tree.leaves() == [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22' ] assert expected == produced.tree
def test_nested_sns_schema(): produced = example2tree('maz-10575-excerpt.rs3') expected = t('interpretation', [('N', [('circumstance', [ ('S', ['eins']), ('N', [('contrast', [('N', ['zwei']), ('N', [('cause', [('N', ['drei']), ('S', ['vier'])])])])]) ])]), ('S', ['fuenf'])]) assert produced.edu_strings == produced.tree.leaves() == [ 'eins', 'zwei', 'drei', 'vier', 'fuenf' ] assert expected == produced.tree
def make_rel2par(nuc_or_sat_subtree): if is_root(nuc_or_sat_subtree): raise ValueError("Root node can't have a relation.") subtree_root_label = nuc_or_sat_subtree.label() parent_label = nuc_or_sat_subtree.parent().label() if subtree_root_label == 'S': return t('rel2par', [parent_label]) elif subtree_root_label == 'N': siblings = get_siblings(nuc_or_sat_subtree) root = nuc_or_sat_subtree.root() sibling_labels = [root[sib].label() for sib in siblings] if len(siblings) == 1 and sibling_labels[0] == 'S': return t('rel2par', ['span']) elif all([label == 'N' for label in sibling_labels]): return t('rel2par', [parent_label]) else: raise ValueError( "Can't mix sibling types. Expected 'N' or 'S', got: {}".format( sibling_labels)) else: raise ValueError( "Unknown nuclearity. Expected 'N' or 'S', got: {}".format( subtree_root_label))
def dis2tree(dis_tree, wrap_tree=False): assert get_tree_type(dis_tree) in SUBTREE_TYPES, "tree_type: {}".format( get_tree_type(dis_tree)) if get_node_type(dis_tree) == 'leaf': return leaf2tree(dis_tree) if is_root(dis_tree): children = dis_tree[1:] else: children = dis_tree[2:] child_types = get_child_types(children) if len(child_types) == 1: # this is a multinuc relation assert NUC in child_types, "child_types: {}".format(child_types) assert len(child_types[NUC]) > 1, "len: {}".format( len(child_types[NUC])) subtrees = [ dis2tree(children[child_id], wrap_tree=True) for child_id in child_types[NUC] ] # all subtrees of a multinuc have the same relation, so we can just read it from the first one reltype = get_relation_type(children[0]) else: # this is a nucleus-satellite relation assert len(child_types) == 2, "child_types: {}".format(child_types) assert NUC in child_types and SAT in child_types, "child_types: {}".format( child_types) assert len(child_types[NUC]) == 1 and len(child_types[SAT]) == 1, \ "child_types: {}".format(child_types) nuc_child_id = child_types[NUC][0] nuc_subtree = dis2tree(children[nuc_child_id], wrap_tree=True) sat_child_id = child_types[SAT][0] sat_child = children[sat_child_id] sat_subtree = dis2tree(sat_child, wrap_tree=True) # determine order of subtrees if nuc_child_id < sat_child_id: subtrees = [nuc_subtree, sat_subtree] else: subtrees = [sat_subtree, nuc_subtree] # the relation type is only stored in the satellite reltype = get_relation_type(sat_child) rst_tree = t(reltype, subtrees) return get_wrapped_tree(dis_tree, rst_tree, wrap_tree=wrap_tree)
def test_rs3filewriter_nucsat(): """A DGParentedTree with one nuc-sat relation is correctly converted into an RS3 file and back.""" input_tree = t("circumstance", [("S", ["foo"]), ("N", ["bar"])]) expected_output_tree = example2tree("foo-bar-circ-foo-to-bar.rs3") tempfile = NamedTemporaryFile() RS3FileWriter(input_tree, output_filepath=tempfile.name) produced_output_tree = RSTTree(tempfile.name) assert produced_output_tree.edu_strings == produced_output_tree.tree.leaves( ) == ['foo', 'bar'] assert input_tree == expected_output_tree.tree == produced_output_tree.tree input_tree = t("circumstance", [("N", ["foo"]), ("S", ["bar"])]) expected_output_tree = example2tree("foo-bar-circ-bar-to-foo.rs3") tempfile = NamedTemporaryFile() RS3FileWriter(input_tree, output_filepath=tempfile.name) produced_output_tree = RSTTree(tempfile.name) assert produced_output_tree.edu_strings == produced_output_tree.tree.leaves( ) == ['foo', 'bar'] assert input_tree == expected_output_tree.tree == produced_output_tree.tree
def test_t(): assert t("", []) == DGParentedTree("", []) assert t("") == DGParentedTree("", []) assert t("foo", []) == DGParentedTree("foo", []) assert t("foo") == DGParentedTree("foo", []) assert t("foo", ["bar"]) == DGParentedTree("foo", ["bar"]) assert t("foo", ["bar", "baz"]) == DGParentedTree("foo", ["bar", "baz"])
def test_single_nss_schema_topspan(): """It doesn't matter if there's a span above a N-S-S schema.""" produced1 = example2tree('n-s-s-schema-eins-zwei-drei.rs3') produced2 = example2tree('n-s-s-schema-eins-zwei-drei-plus-top-span.rs3') expected = t('background', [('N', [('elaboration', [('N', ['eins']), ('S', ['zwei'])])]), ('S', ['drei'])]) assert produced1.edu_strings == produced1.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert produced2.edu_strings == produced2.tree.leaves() == [ 'eins', 'zwei', 'drei' ] assert expected == produced1.tree == produced2.tree
def test_fix_one_edu_span(): """A span consisting of only one EDU is parsed correctly.""" produced = example2tree('one-edu-span.rs3', rs3tree_dir=RS3TREE_DIR) expected = t('preparation', [ ('S', ['13']), ('N', [('antithesis', [('S', ['14']), ('N', [('interpretation', [('N', ['15']), ('S', ['16'])])])])]) ]) assert no_span_nodes(produced.tree) assert produced.edu_strings == produced.tree.leaves() == [ '13', '14', '15', '16' ] assert expected == produced.tree
def test_single_nucsat_relation(): produced = example2tree("foo-bar-circ-foo-to-bar.rs3") expected = t("circumstance", [("S", ["foo"]), ("N", ["bar"])]) assert produced.edu_strings == produced.tree.leaves() == ['foo', 'bar'] assert expected == produced.tree produced = example2tree("foo-bar-elab-foo-to-bar.rs3") expected = t("elaboration", [("S", ["foo"]), ("N", ["bar"])]) assert produced.edu_strings == produced.tree.leaves() == ['foo', 'bar'] assert expected == produced.tree produced = example2tree("foo-bar-circ-bar-to-foo.rs3") expected = t("circumstance", [("N", ["foo"]), ("S", ["bar"])]) assert produced.edu_strings == produced.tree.leaves() == ['foo', 'bar'] assert expected == produced.tree produced = example2tree("foo-bar-elab-bar-to-foo.rs3") expected = t("elaboration", [("N", ["foo"]), ("S", ["bar"])]) assert produced.edu_strings == produced.tree.leaves() == ['foo', 'bar'] assert expected == produced.tree