natural language toolkit verbnet corpus reader c 20012023 nltk project edward loper edlopergmail com url https www nltk org for license information see license txt an nltk interface to the verbnet verb lexicon for details about verbnet see https verbs colorado edumpalmerprojectsverbnet html an nltk interface to the verbnet verb lexicon from the verbnet site verbnet vn kipperschuler 2006 is the largest online verb lexicon currently available for english it is a hierarchical domainindependent broadcoverage verb lexicon with mappings to other lexical resources such as wordnet miller 1990 fellbaum 1998 xtag xtag research group 2001 and framenet baker et al 1998 for details about verbnet see https verbs colorado edumpalmerprojectsverbnet html no unicode encoding param since the data files are all xml a dictionary mapping from verb lemma strings to lists of verbnet class identifiers self wordnettoclass defaultdictlist a dictionary mapping from class identifiers to corresponding file identifiers the keys of this dictionary provide a complete list of all classes and subclasses self shortidtolongid initialize the dictionaries use the quick regexpbased method instead of the slow xmlbased method because it runs 230 times faster self quickindex longidre re compiler d regular expression that matches shortids indexre re compile r member name wn r vnsubclass id return a list of all verb lemmas that appear in any class or in the classid if specified xx should this include subclass members return a list of all wordnet identifiers that appear in any class or in classid if specified xx should this include subclass members return a list of the verbnet class identifiers if a file identifier is specified then return only the verbnet class identifiers for classes and subclasses defined by that file if a lemma is specified then return only verbnet class identifiers for classes that contain that lemma as a member if a wordnetid is specified then return only identifiers for classes that contain that wordnetid as a member if a classid is specified then return only identifiers for subclasses of the specified verbnet class if nothing is specified return all classids within verbnet returns verbnet class elementtree return an elementtree containing the xml for the specified verbnet class param fileidorclassid an identifier specifying which class should be returned can be a file identifier such as put9 1 xml or a verbnet class identifier such as put9 1 or a short verbnet class identifier such as 9 1 file identifier just return the xml class identifier get the xml and find the right elt return a list of fileids that make up this corpus if vnclassids is specified then return the fileids that make up the specified verbnet classes given a verbnet class this method returns verbnet frames the members returned are 1 example 2 description 3 syntax 4 semantics param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class return frames a list of frame dictionaries returns subclass ids if any exist given a verbnet class this method returns subclass ids if they exist in a list of strings param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class return list of subclasses returns thematic roles participating in a verbnet class members returned as part of roles are 1 type 2 modifiers param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class return themroles a list of thematic roles in the verbnet class index initialization initialize the indexes lemmatoclass wordnettoclass and classtofileid by scanning through the corpus fileids this is fast if elementtree uses the c implementation 0 1 secs but quite slow 10 secs if only the python implementation is available helper for index vnclass xmltree getid self classtofileidvnclass fileid self shortidtolongidself shortidvnclass vnclass for member in xmltree findallmembersmember self lemmatoclassmember getname appendvnclass for wn in member getwn split self wordnettoclasswn appendvnclass for subclass in xmltree findallsubclassesvnsubclass self indexhelpersubclass fileid def quickindexself nb if we got rid of wordnettoclass this would run 23 times faster for fileid in self fileids vnclass fileid 4 strip the xml self classtofileidvnclass fileid self shortidtolongidself shortidvnclass vnclass with self openfileid as fp for m in self indexre finditerfp read groups m groups if groups0 is not none self lemmatoclassgroups0 appendvnclass for wn in groups1 split self wordnettoclasswn appendvnclass elif groups2 is not none self classtofileidgroups2 fileid vnclass groups2 for member elts self shortidtolongidself shortidvnclass vnclass else assert false unexpected match condition identifier conversion def longidself shortid returns shortid of a verbnet class given a long verbnet class identifier eg confess37 10 map it to a short id eg 37 10 if longid is already a short id then return it asis if self shortidre matchlongid return longid it s already a shortid m self longidre matchlongid if m return m group2 else raise valueerrorvnclass identifier r not found longid frame access utility functions def getsemanticswithinframeself vnframe semanticswithinsingleframe for pred in vnframe findallsemanticspred arguments type arg gettype value arg getvalue for arg in pred findallargsarg semanticswithinsingleframe append predicatevalue pred getvalue arguments arguments negated pred getbool return semanticswithinsingleframe def getexamplewithinframeself vnframe exampleelement vnframe findexamplesexample if exampleelement is not none exampletext exampleelement text else exampletext return exampletext def getdescriptionwithinframeself vnframe descriptionelement vnframe finddescription return primary descriptionelement attribprimary secondary descriptionelement getsecondary def getsyntacticlistwithinframeself vnframe syntaxwithinsingleframe for elt in vnframe findsyntax postag elt tag modifiers dict modifiersvalue elt getvalue if value in elt attrib else modifiersselrestrs value restr getvalue type restr gettype for restr in elt findallselrestrsselrestr modifierssynrestrs value restr getvalue type restr gettype for restr in elt findallsynrestrssynrestr syntaxwithinsingleframe append postag postag modifiers modifiers return syntaxwithinsingleframe pretty printing def pprintself vnclass if isinstancevnclass str vnclass self vnclassvnclass s vnclass getid n s self pprintsubclassesvnclass indent n s self pprintmembersvnclass indent n s thematic roles n s self pprintthemrolesvnclass indent n s frames n s self pprintframesvnclass indent return s def pprintsubclassesself vnclass indent if isinstancevnclass str vnclass self vnclassvnclass subclasses self subclassesvnclass if not subclasses subclasses none s subclasses joinsubclasses return textwrap fill s 70 initialindentindent subsequentindentindent def pprintmembersself vnclass indent if isinstancevnclass str vnclass self vnclassvnclass members self lemmasvnclass if not members members none s members joinmembers return textwrap fill s 70 initialindentindent subsequentindentindent def pprintthemrolesself vnclass indent if isinstancevnclass str vnclass self vnclassvnclass pieces for themrole in self themrolesvnclass piece indent themrole gettype modifiers modifiervalue modifiertype for modifier in themrolemodifiers if modifiers piece format joinmodifiers pieces appendpiece return n joinpieces def pprintframesself vnclass indent if isinstancevnclass str vnclass self vnclassvnclass pieces for vnframe in self framesvnclass pieces appendself pprintsingleframevnframe indent return n joinpieces def pprintsingleframeself vnframe indent framestring self pprintdescriptionwithinframevnframe indent n framestring self pprintexamplewithinframevnframe indent n framestring self pprintsyntaxwithinframevnframe indent syntax n framestring indent semantics n framestring self pprintsemanticswithinframevnframe indent return framestring def pprintexamplewithinframeself vnframe indent if vnframeexample return indent example vnframeexample def pprintdescriptionwithinframeself vnframe indent description indent vnframedescriptionprimary if vnframedescriptionsecondary description formatvnframedescriptionsecondary return description def pprintsyntaxwithinframeself vnframe indent pieces for element in vnframesyntax piece elementpostag modifierlist if value in elementmodifiers and elementmodifiersvalue modifierlist appendelementmodifiersvalue modifierlist formatrestrvalue restrtype for restr in elementmodifiersselrestrs elementmodifierssynrestrs if modifierlist piece format joinmodifierlist pieces appendpiece return indent joinpieces def pprintsemanticswithinframeself vnframe indent pieces for predicate in vnframesemantics arguments argumentvalue for argument in predicatearguments pieces append f if predicate negated else predicate predicatevalue joinarguments return n joinfindent piece for piece in pieces natural language toolkit verbnet corpus reader c 2001 2023 nltk project edward loper edloper gmail com url https www nltk org for license information see license txt an nltk interface to the verbnet verb lexicon for details about verbnet see https verbs colorado edu mpalmer projects verbnet html an nltk interface to the verbnet verb lexicon from the verbnet site verbnet vn kipper schuler 2006 is the largest on line verb lexicon currently available for english it is a hierarchical domain independent broad coverage verb lexicon with mappings to other lexical resources such as wordnet miller 1990 fellbaum 1998 xtag xtag research group 2001 and framenet baker et al 1998 for details about verbnet see https verbs colorado edu mpalmer projects verbnet html no unicode encoding param since the data files are all xml a dictionary mapping from verb lemma strings to lists of verbnet class identifiers a dictionary mapping from wordnet identifier strings to lists of verbnet class identifiers a dictionary mapping from class identifiers to corresponding file identifiers the keys of this dictionary provide a complete list of all classes and subclasses initialize the dictionaries use the quick regexp based method instead of the slow xml based method because it runs 2 30 times faster regular expression that matches and decomposes longids regular expression that matches shortids regular expression used by _index to quickly scan the corpus for basic information return a list of all verb lemmas that appear in any class or in the classid if specified xx should this include subclass members return a list of all wordnet identifiers that appear in any class or in classid if specified xx should this include subclass members return a list of the verbnet class identifiers if a file identifier is specified then return only the verbnet class identifiers for classes and subclasses defined by that file if a lemma is specified then return only verbnet class identifiers for classes that contain that lemma as a member if a wordnetid is specified then return only identifiers for classes that contain that wordnetid as a member if a classid is specified then return only identifiers for subclasses of the specified verbnet class if nothing is specified return all classids within verbnet returns verbnet class elementtree return an elementtree containing the xml for the specified verbnet class param fileid_or_classid an identifier specifying which class should be returned can be a file identifier such as put 9 1 xml or a verbnet class identifier such as put 9 1 or a short verbnet class identifier such as 9 1 file identifier just return the xml class identifier get the xml and find the right elt we saw it during _index return a list of fileids that make up this corpus if vnclass_ids is specified then return the fileids that make up the specified verbnet class es given a verbnet class this method returns verbnet frames the members returned are 1 example 2 description 3 syntax 4 semantics param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class return frames a list of frame dictionaries returns subclass ids if any exist given a verbnet class this method returns subclass ids if they exist in a list of strings param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class return list of subclasses returns thematic roles participating in a verbnet class members returned as part of roles are 1 type 2 modifiers param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class return themroles a list of thematic roles in the verbnet class index initialization initialize the indexes _lemma_to_class _wordnet_to_class and _class_to_fileid by scanning through the corpus fileids this is fast if elementtree uses the c implementation 0 1 secs but quite slow 10 secs if only the python implementation is available helper for _index initialize the indexes _lemma_to_class _wordnet_to_class and _class_to_fileid by scanning through the corpus fileids this doesn t do proper xml parsing but is good enough to find everything in the standard verbnet corpus and it runs about 30 times faster than xml parsing with the python elementtree only 2 3 times faster if elementtree uses the c implementation nb if we got rid of wordnet_to_class this would run 2 3 times faster strip the xml for member elts identifier conversion returns longid of a verbnet class given a short verbnet class identifier eg 37 10 map it to a long id eg confess 37 10 if shortid is already a long id then return it as is it s already a longid returns shortid of a verbnet class given a long verbnet class identifier eg confess 37 10 map it to a short id eg 37 10 if longid is already a short id then return it as is it s already a shortid frame access utility functions returns semantics within a single frame a utility function to retrieve semantics within a frame in verbnet members of the semantics dictionary 1 predicate value 2 arguments param vnframe an elementtree containing the xml contents of a verbnet frame return semantics semantics dictionary returns example within a frame a utility function to retrieve an example within a frame in verbnet param vnframe an elementtree containing the xml contents of a verbnet frame return example_text the example sentence for this particular frame returns member description within frame a utility function to retrieve a description of participating members within a frame in verbnet param vnframe an elementtree containing the xml contents of a verbnet frame return description a description dictionary with members primary and secondary returns semantics within a frame a utility function to retrieve semantics within a frame in verbnet members of the syntactic dictionary 1 pos tag 2 modifiers param vnframe an elementtree containing the xml contents of a verbnet frame return syntax_within_single_frame pretty printing returns pretty printed version of a verbnet class return a string containing a pretty printed representation of the given verbnet class param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class returns pretty printed version of subclasses of verbnet class return a string containing a pretty printed representation of the given verbnet class s subclasses param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class returns pretty printed version of members in a verbnet class return a string containing a pretty printed representation of the given verbnet class s member verbs param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class returns pretty printed version of thematic roles in a verbnet class return a string containing a pretty printed representation of the given verbnet class s thematic roles param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class returns pretty version of all frames in a verbnet class return a string containing a pretty printed representation of the list of frames within the verbnet class param vnclass a verbnet class identifier or an elementtree containing the xml contents of a verbnet class returns pretty printed version of a single frame in a verbnet class returns a string containing a pretty printed representation of the given frame param vnframe an elementtree containing the xml contents of a verbnet frame returns pretty printed version of example within frame in a verbnet class return a string containing a pretty printed representation of the given verbnet frame example param vnframe an elementtree containing the xml contents of a verbnet frame returns pretty printed version of a verbnet frame description return a string containing a pretty printed representation of the given verbnet frame description param vnframe an elementtree containing the xml contents of a verbnet frame returns pretty printed version of syntax within a frame in a verbnet class return a string containing a pretty printed representation of the given verbnet frame syntax param vnframe an elementtree containing the xml contents of a verbnet frame returns a pretty printed version of semantics within frame in a verbnet class return a string containing a pretty printed representation of the given verbnet frame semantics param vnframe an elementtree containing the xml contents of a verbnet frame
import re
import textwrap
from collections import defaultdict

from nltk.corpus.reader.xmldocs import XMLCorpusReader


class VerbnetCorpusReader(XMLCorpusReader):
    

    
    def __init__(self, root, fileids, wrap_etree=False):
        XMLCorpusReader.__init__(self, root, fileids, wrap_etree)

        self._lemma_to_class = defaultdict(list)
        

        self._wordnet_to_class = defaultdict(list)
        

        self._class_to_fileid = {}
        

        self._shortid_to_longid = {}

        
        
        
        self._quick_index()

    _LONGID_RE = re.compile(r"([^\-\.]*)-([\d+.\-]+)$")
    

    _SHORTID_RE = re.compile(r"[\d+.\-]+$")
    

    _INDEX_RE = re.compile(
        r'<MEMBER name="\??([^"]+)" wn="([^"]*)"[^>]+>|' r'<VNSUBCLASS ID="([^"]+)"/?>'
    )
    

    def lemmas(self, vnclass=None):
        
        if vnclass is None:
            return sorted(self._lemma_to_class.keys())
        else:
            
            if isinstance(vnclass, str):
                vnclass = self.vnclass(vnclass)
            return [member.get("name") for member in vnclass.findall("MEMBERS/MEMBER")]

    def wordnetids(self, vnclass=None):
        
        if vnclass is None:
            return sorted(self._wordnet_to_class.keys())
        else:
            
            if isinstance(vnclass, str):
                vnclass = self.vnclass(vnclass)
            return sum(
                (
                    member.get("wn", "").split()
                    for member in vnclass.findall("MEMBERS/MEMBER")
                ),
                [],
            )

    def classids(self, lemma=None, wordnetid=None, fileid=None, classid=None):
        
        if fileid is not None:
            return [c for (c, f) in self._class_to_fileid.items() if f == fileid]
        elif lemma is not None:
            return self._lemma_to_class[lemma]
        elif wordnetid is not None:
            return self._wordnet_to_class[wordnetid]
        elif classid is not None:
            xmltree = self.vnclass(classid)
            return [
                subclass.get("ID")
                for subclass in xmltree.findall("SUBCLASSES/VNSUBCLASS")
            ]
        else:
            return sorted(self._class_to_fileid.keys())

    def vnclass(self, fileid_or_classid):
        
        
        if fileid_or_classid in self._fileids:
            return self.xml(fileid_or_classid)

        
        classid = self.longid(fileid_or_classid)
        if classid in self._class_to_fileid:
            fileid = self._class_to_fileid[self.longid(classid)]
            tree = self.xml(fileid)
            if classid == tree.get("ID"):
                return tree
            else:
                for subclass in tree.findall(".//VNSUBCLASS"):
                    if classid == subclass.get("ID"):
                        return subclass
                else:
                    assert False  

        else:
            raise ValueError(f"Unknown identifier {fileid_or_classid}")

    def fileids(self, vnclass_ids=None):
        
        if vnclass_ids is None:
            return self._fileids
        elif isinstance(vnclass_ids, str):
            return [self._class_to_fileid[self.longid(vnclass_ids)]]
        else:
            return [
                self._class_to_fileid[self.longid(vnclass_id)]
                for vnclass_id in vnclass_ids
            ]

    def frames(self, vnclass):
        
        if isinstance(vnclass, str):
            vnclass = self.vnclass(vnclass)
        frames = []
        vnframes = vnclass.findall("FRAMES/FRAME")
        for vnframe in vnframes:
            frames.append(
                {
                    "example": self._get_example_within_frame(vnframe),
                    "description": self._get_description_within_frame(vnframe),
                    "syntax": self._get_syntactic_list_within_frame(vnframe),
                    "semantics": self._get_semantics_within_frame(vnframe),
                }
            )
        return frames

    def subclasses(self, vnclass):
        
        if isinstance(vnclass, str):
            vnclass = self.vnclass(vnclass)

        subclasses = [
            subclass.get("ID") for subclass in vnclass.findall("SUBCLASSES/VNSUBCLASS")
        ]
        return subclasses

    def themroles(self, vnclass):
        
        if isinstance(vnclass, str):
            vnclass = self.vnclass(vnclass)

        themroles = []
        for trole in vnclass.findall("THEMROLES/THEMROLE"):
            themroles.append(
                {
                    "type": trole.get("type"),
                    "modifiers": [
                        {"value": restr.get("Value"), "type": restr.get("type")}
                        for restr in trole.findall("SELRESTRS/SELRESTR")
                    ],
                }
            )
        return themroles

    
    
    

    def _index(self):
        
        for fileid in self._fileids:
            self._index_helper(self.xml(fileid), fileid)

    def _index_helper(self, xmltree, fileid):
        
        vnclass = xmltree.get("ID")
        self._class_to_fileid[vnclass] = fileid
        self._shortid_to_longid[self.shortid(vnclass)] = vnclass
        for member in xmltree.findall("MEMBERS/MEMBER"):
            self._lemma_to_class[member.get("name")].append(vnclass)
            for wn in member.get("wn", "").split():
                self._wordnet_to_class[wn].append(vnclass)
        for subclass in xmltree.findall("SUBCLASSES/VNSUBCLASS"):
            self._index_helper(subclass, fileid)

    def _quick_index(self):
        
        
        
        for fileid in self._fileids:
            vnclass = fileid[:-4]  
            self._class_to_fileid[vnclass] = fileid
            self._shortid_to_longid[self.shortid(vnclass)] = vnclass
            with self.open(fileid) as fp:
                for m in self._INDEX_RE.finditer(fp.read()):
                    groups = m.groups()
                    if groups[0] is not None:
                        self._lemma_to_class[groups[0]].append(vnclass)
                        for wn in groups[1].split():
                            self._wordnet_to_class[wn].append(vnclass)
                    elif groups[2] is not None:
                        self._class_to_fileid[groups[2]] = fileid
                        vnclass = groups[2]  
                        self._shortid_to_longid[self.shortid(vnclass)] = vnclass
                    else:
                        assert False, "unexpected match condition"

    
    
    

    def longid(self, shortid):
        
        if self._LONGID_RE.match(shortid):
            return shortid  
        elif not self._SHORTID_RE.match(shortid):
            raise ValueError("vnclass identifier %r not found" % shortid)
        try:
            return self._shortid_to_longid[shortid]
        except KeyError as e:
            raise ValueError("vnclass identifier %r not found" % shortid) from e

    def shortid(self, longid):
        
        if self._SHORTID_RE.match(longid):
            return longid  
        m = self._LONGID_RE.match(longid)
        if m:
            return m.group(2)
        else:
            raise ValueError("vnclass identifier %r not found" % longid)

    
    
    

    def _get_semantics_within_frame(self, vnframe):
        
        semantics_within_single_frame = []
        for pred in vnframe.findall("SEMANTICS/PRED"):
            arguments = [
                {"type": arg.get("type"), "value": arg.get("value")}
                for arg in pred.findall("ARGS/ARG")
            ]
            semantics_within_single_frame.append(
                {
                    "predicate_value": pred.get("value"),
                    "arguments": arguments,
                    "negated": pred.get("bool") == "!",
                }
            )
        return semantics_within_single_frame

    def _get_example_within_frame(self, vnframe):
        
        example_element = vnframe.find("EXAMPLES/EXAMPLE")
        if example_element is not None:
            example_text = example_element.text
        else:
            example_text = ""
        return example_text

    def _get_description_within_frame(self, vnframe):
        
        description_element = vnframe.find("DESCRIPTION")
        return {
            "primary": description_element.attrib["primary"],
            "secondary": description_element.get("secondary", ""),
        }

    def _get_syntactic_list_within_frame(self, vnframe):
        
        syntax_within_single_frame = []
        for elt in vnframe.find("SYNTAX"):
            pos_tag = elt.tag
            modifiers = dict()
            modifiers["value"] = elt.get("value") if "value" in elt.attrib else ""
            modifiers["selrestrs"] = [
                {"value": restr.get("Value"), "type": restr.get("type")}
                for restr in elt.findall("SELRESTRS/SELRESTR")
            ]
            modifiers["synrestrs"] = [
                {"value": restr.get("Value"), "type": restr.get("type")}
                for restr in elt.findall("SYNRESTRS/SYNRESTR")
            ]
            syntax_within_single_frame.append(
                {"pos_tag": pos_tag, "modifiers": modifiers}
            )
        return syntax_within_single_frame

    
    
    

    def pprint(self, vnclass):
        
        if isinstance(vnclass, str):
            vnclass = self.vnclass(vnclass)

        s = vnclass.get("ID") + "\n"
        s += self.pprint_subclasses(vnclass, indent="  ") + "\n"
        s += self.pprint_members(vnclass, indent="  ") + "\n"
        s += "  Thematic roles:\n"
        s += self.pprint_themroles(vnclass, indent="    ") + "\n"
        s += "  Frames:\n"
        s += self.pprint_frames(vnclass, indent="    ")
        return s

    def pprint_subclasses(self, vnclass, indent=""):
        
        if isinstance(vnclass, str):
            vnclass = self.vnclass(vnclass)

        subclasses = self.subclasses(vnclass)
        if not subclasses:
            subclasses = ["(none)"]
        s = "Subclasses: " + " ".join(subclasses)
        return textwrap.fill(
            s, 70, initial_indent=indent, subsequent_indent=indent + "  "
        )

    def pprint_members(self, vnclass, indent=""):
        
        if isinstance(vnclass, str):
            vnclass = self.vnclass(vnclass)

        members = self.lemmas(vnclass)
        if not members:
            members = ["(none)"]
        s = "Members: " + " ".join(members)
        return textwrap.fill(
            s, 70, initial_indent=indent, subsequent_indent=indent + "  "
        )

    def pprint_themroles(self, vnclass, indent=""):
        
        if isinstance(vnclass, str):
            vnclass = self.vnclass(vnclass)

        pieces = []
        for themrole in self.themroles(vnclass):
            piece = indent + "* " + themrole.get("type")
            modifiers = [
                modifier["value"] + modifier["type"]
                for modifier in themrole["modifiers"]
            ]
            if modifiers:
                piece += "[{}]".format(" ".join(modifiers))
            pieces.append(piece)
        return "\n".join(pieces)

    def pprint_frames(self, vnclass, indent=""):
        
        if isinstance(vnclass, str):
            vnclass = self.vnclass(vnclass)
        pieces = []
        for vnframe in self.frames(vnclass):
            pieces.append(self._pprint_single_frame(vnframe, indent))
        return "\n".join(pieces)

    def _pprint_single_frame(self, vnframe, indent=""):
        
        frame_string = self._pprint_description_within_frame(vnframe, indent) + "\n"
        frame_string += self._pprint_example_within_frame(vnframe, indent + " ") + "\n"
        frame_string += (
            self._pprint_syntax_within_frame(vnframe, indent + "  Syntax: ") + "\n"
        )
        frame_string += indent + "  Semantics:\n"
        frame_string += self._pprint_semantics_within_frame(vnframe, indent + "    ")
        return frame_string

    def _pprint_example_within_frame(self, vnframe, indent=""):
        
        if vnframe["example"]:
            return indent + " Example: " + vnframe["example"]

    def _pprint_description_within_frame(self, vnframe, indent=""):
        
        description = indent + vnframe["description"]["primary"]
        if vnframe["description"]["secondary"]:
            description += " ({})".format(vnframe["description"]["secondary"])
        return description

    def _pprint_syntax_within_frame(self, vnframe, indent=""):
        
        pieces = []
        for element in vnframe["syntax"]:
            piece = element["pos_tag"]
            modifier_list = []
            if "value" in element["modifiers"] and element["modifiers"]["value"]:
                modifier_list.append(element["modifiers"]["value"])
            modifier_list += [
                "{}{}".format(restr["value"], restr["type"])
                for restr in (
                    element["modifiers"]["selrestrs"]
                    + element["modifiers"]["synrestrs"]
                )
            ]
            if modifier_list:
                piece += "[{}]".format(" ".join(modifier_list))
            pieces.append(piece)

        return indent + " ".join(pieces)

    def _pprint_semantics_within_frame(self, vnframe, indent=""):
        
        pieces = []
        for predicate in vnframe["semantics"]:
            arguments = [argument["value"] for argument in predicate["arguments"]]
            pieces.append(
                f"{'¬' if predicate['negated'] else ''}{predicate['predicate_value']}({', '.join(arguments)})"
            )
        return "\n".join(f"{indent}* {piece}" for piece in pieces)