"""Documentation links for the UPOS and basic dependency labels in a parse.""" import html POS_NAMES = { "ADJ": "Adjective", "ADP": "Adposition", "ADV": "Adverb", "AUX": "Auxiliary", "CCONJ": "Coordinating conjunction", "DET": "Determiner", "INTJ": "Interjection", "NOUN": "Noun", "NUM": "Numeral", "PART": "Particle", "PRON": "Pronoun", "PROPN": "Proper noun", "PUNCT": "Punctuation", "SCONJ": "Subordinating conjunction", "SYM": "Symbol", "VERB": "Verb", "X": "Other", } RELATION_NAMES = { "nsubj": "Nominal subject", "obj": "Object", "iobj": "Indirect object", "csubj": "Clausal subject", "ccomp": "Clausal complement", "xcomp": "Open clausal complement", "obl": "Oblique nominal", "vocative": "Vocative", "expl": "Expletive", "dislocated": "Dislocated element", "advcl": "Adverbial clause modifier", "advmod": "Adverbial modifier", "discourse": "Discourse element", "nmod": "Nominal modifier", "appos": "Appositional modifier", "nummod": "Numeric modifier", "acl": "Clausal modifier of a noun", "amod": "Adjectival modifier", "det": "Determiner", "clf": "Classifier", "case": "Case marking", "conj": "Conjunct", "cc": "Coordinating conjunction", "fixed": "Fixed multiword expression", "flat": "Flat multiword expression", "compound": "Compound", "list": "List", "parataxis": "Parataxis", "orphan": "Orphan", "goeswith": "Goes with", "reparandum": "Overridden disfluency", "punct": "Punctuation", "root": "Root", "dep": "Unspecified dependency", "aux": "Auxiliary", "cop": "Copula", "mark": "Marker", } # Verified universal subtype pages. Other subtypes link to their base relation # rather than assuming that a universal page exists for a language-specific label. SUBTYPE_NAMES = { "acl:relcl": "Relative clause modifier", "aux:pass": "Passive auxiliary", "csubj:pass": "Clausal passive subject", "nsubj:pass": "Passive nominal subject", "nmod:poss": "Possessive nominal modifier", } # Curated Universal Dependencies morphological features for English and German. FEATURE_NAMES = { # 1. Core morphological features "Case": "Case (e.g. nominative, accusative, dative, genitive)", "Gender": "Gender (masculine, feminine, neuter)", "Number": "Number (singular, plural)", "Person": "Person (first, second, third)", "Tense": "Tense (past, present, future)", "Mood": "Mood (indicative, imperative, subjunctive)", "VerbForm": "Verb form (finite, infinitive, participle, gerund)", "Degree": "Degree of comparison (positive, comparative, superlative)", # 2. Additional relevant features "PronType": "Pronominal type (personal, relative, demonstrative, etc.)", "Definite": "Definiteness (definite, indefinite)", "Poss": "Possessive marker/determiner", "Reflex": "Reflexive pronoun/marker", "NumType": "Numeral type (cardinal, ordinal, etc.)", "Voice": "Voice (active, passive)", "Aspect": "Aspect (aspectual distinctions)", "Polarity": "Polarity (positive, negative)", # 3. Other features worth knowing "Abbr": "Abbreviation", "Foreign": "Foreign word", "Typo": "Typographical error / unnormalized spelling", "ExtPos": "External part of speech", } def render_ud_help(conllu_text, word_links_html=""): """Render expanded Help with deduplicated labels used by visible word rows.""" pos, relations, features = set(), set(), set() for line in conllu_text.splitlines(): fields = line.split("\t") # The renderer excludes multiword headers and empty nodes by default. if len(fields) != 10 or not fields[0].isdigit(): continue if fields[3] in POS_NAMES: pos.add(fields[3]) if fields[7].split(":")[0] in RELATION_NAMES: relations.add(fields[7]) # FEATS is column 5 (0-indexed) feats_val = fields[5] if feats_val and feats_val != "_": for feat_pair in feats_val.split("|"): if "=" in feat_pair: feat_name = feat_pair.split("=")[0].strip() if feat_name in FEATURE_NAMES: features.add(feat_name) def link(label, name, path): return ( f'
  • {html.escape(label)}' f' — {html.escape(name)}
  • ' ) tags = "".join(link(tag, POS_NAMES[tag], "pos/" + tag) for tag in sorted(pos)) dependencies = [] for relation in sorted(relations): base = relation.split(":")[0] if relation in SUBTYPE_NAMES: name, page = SUBTYPE_NAMES[relation], relation.replace(":", "-") else: name, page = RELATION_NAMES[base], base if ":" in relation: name += " (subtype; link explains the base relation)" dependencies.append(link(relation, name, "dep/" + page)) feat_links = "".join( link(feat, FEATURE_NAMES[feat], "feat/" + feat) for feat in sorted(features) ) if not tags and not dependencies and not feat_links: return "" columns_html = "" if tags: columns_html += '
    POS tags in this sentence
    ' if dependencies: columns_html += '
    Relations in this sentence
    ' if feat_links: columns_html += '
    Morphological features in this sentence
    ' if word_links_html: columns_html += word_links_html return ( '
    Help' f'
    {columns_html}
    ' )