API reference

Corpus

The corpus store: several CoNLL-U sources behind one search and edit API.

This is the API the MCP server exposes, and it can be used directly from Python (e.g. by llmaligner) without MCP. All public methods are thread-safe.

mcparser.corpus.store.COLUMN_ALIASES = {'arc': 'head', 'features': 'feats', 'morphology': 'feats', 'pos': 'upos', 'relation': 'deprel', 'segmentation': 'form', 'tokenisation': 'form', 'tokenization': 'form'}

Friendly names accepted wherever a column is expected.

class mcparser.corpus.store.CorpusStore(autosave=True)[source]

Bases: object

A set of named CoNLL-U sources.

Read-only sources (ro) hold trusted examples such as treebank training data. Writable sources (rw) hold predictions that agents edit; every change is saved immediately when autosave is on.

Parameters:

autosave (bool)

add_text_corpus(name, paths)[source]

Register plain-text files as a corpus of unannotated evidence (indexed on first use).

Parameters:
  • name (str)

  • paths (list[Path | str])

Return type:

TextCorpus

text_corpus(name=None)[source]

The named corpus, or the only one when no name is given.

Parameters:

name (str | None)

Return type:

TextCorpus

corpus_find(form, corpus=None, loose=False, examples=3, width=6, neighbours=5, affixed=5)[source]

How form is used in an unannotated corpus (see TextCorpus.find()).

Parameters:
  • form (str)

  • corpus (str | None)

  • loose (bool)

  • examples (int)

  • width (int)

  • neighbours (int)

  • affixed (int)

Return type:

CorpusSearch

save(source=None)[source]

Save one writable source or alignment set, or all of them. Returns the names saved.

Parameters:

source (str | None)

Return type:

list[str]

reload(source)[source]

Reload a source from disk, discarding unsaved changes.

Parameters:

source (str)

Return type:

SourceInfo

get_context(source, sent_id, before=2, after=2)[source]

The sentence and its neighbours in file order.

Parameters:
  • source (str)

  • sent_id (str)

  • before (int)

  • after (int)

Return type:

list[SentenceSummary]

find_tokens(form=None, lemma=None, upos=None, xpos=None, feats=None, deprel=None, root=None, suffix=None, previous_form=None, next_form=None, previous_upos=None, next_upos=None, loose=False, sources=None, min_confidence=0.0, exclude_sentence=None, group_by=None, limit=10, window=3)[source]

Find words matching every given criterion.

feats matches words having at least those features. root matches the MISC root attribute (Root= by default). suffix matches word endings, for analogy with unseen forms; previous_form and next_form require the neighbouring words (these three ignore case and diacritics), previous_upos and next_upos their UPOS. Hits are ordered by confidence (in LEMMA/UPOS/XPOS/FEATS), and groups counts all matches.

Parameters:
  • form (str | None)

  • lemma (str | None)

  • upos (str | None)

  • xpos (str | None)

  • feats (str | None)

  • deprel (str | None)

  • root (str | None)

  • suffix (str | None)

  • previous_form (str | None)

  • next_form (str | None)

  • previous_upos (str | None)

  • next_upos (str | None)

  • loose (bool)

  • sources (list[str] | None)

  • min_confidence (float)

  • exclude_sentence (str | None)

  • group_by (list[str] | None)

  • limit (int)

  • window (int)

Return type:

TokenSearch

analyse_form(form, loose=False, previous_form=None, next_form=None, previous_upos=None, next_upos=None, sources=None, min_confidence=0.0, exclude_sentence=None, limit=5)[source]

How a word form is analysed (optionally next to given words or tags): counts of (lemma, upos, xpos, feats) plus examples.

Parameters:
  • form (str)

  • loose (bool)

  • previous_form (str | None)

  • next_form (str | None)

  • previous_upos (str | None)

  • next_upos (str | None)

  • sources (list[str] | None)

  • min_confidence (float)

  • exclude_sentence (str | None)

  • limit (int)

Return type:

TokenSearch

find_multiword(surface, loose=False, sources=None, limit=10)[source]

How a surface token is split into words, and how often it is left unsplit.

Parameters:
  • surface (str)

  • loose (bool)

  • sources (list[str] | None)

  • limit (int)

Return type:

MultiwordSearch

find_arcs(dependent_form=None, dependent_lemma=None, dependent_upos=None, head_form=None, head_lemma=None, head_upos=None, deprel=None, direction=None, loose=False, sources=None, min_confidence=0.0, exclude_sentence=None, limit=10, window=3)[source]

Find dependency arcs by properties of the dependent, the head and the relation.

deprel without a subtype (nmod) also matches subtypes (nmod:gen). Use head_upos="ROOT" to find root words. direction is the side of the dependent on which the head lies.

Parameters:
  • dependent_form (str | None)

  • dependent_lemma (str | None)

  • dependent_upos (str | None)

  • head_form (str | None)

  • head_lemma (str | None)

  • head_upos (str | None)

  • deprel (str | None)

  • direction (Literal['left', 'right', 'root'] | None)

  • loose (bool)

  • sources (list[str] | None)

  • min_confidence (float)

  • exclude_sentence (str | None)

  • limit (int)

  • window (int)

Return type:

ArcSearch

search_sentences(query, sources=None, limit=5, min_confidence=0.0, exclude_sentence=None)[source]

BM25 search over sentence text (accent- and case-insensitive).

Parameters:
  • query (str)

  • sources (list[str] | None)

  • limit (int)

  • min_confidence (float)

  • exclude_sentence (str | None)

Return type:

list[SentenceHit]

allowed_values(column, upos=None, sources=None, limit=100)[source]

Values of UPOS, XPOS, DEPREL or FEATS with their frequencies.

By default only read-only (trusted) sources are counted. With upos, XPOS/DEPREL/FEATS are restricted to words with that UPOS.

Parameters:
  • column (str)

  • upos (str | None)

  • sources (list[str] | None)

  • limit (int)

Return type:

list[ValueCount]

feature_inventory(upos=None, sources=None)[source]

Each morphological feature and its values (optionally for one UPOS).

Parameters:
  • upos (str | None)

  • sources (list[str] | None)

Return type:

dict[str, list[ValueCount]]

feature_conventions(upos, min_count=20, min_share=0.1, sources=None)[source]

Where the trusted data writes a combined feature value (Gender=Masc,Neut) for upos.

One entry per (Case, Number, feature) with at least min_count examples of which at least min_share carry a combined value, most frequent first.

Parameters:
  • upos (str)

  • min_count (int)

  • min_share (float)

  • sources (list[str] | None)

Return type:

list[FeatureConvention]

relation_stats(dependent_lemma, dependent_upos, head_lemma, head_upos, direction, min_total=3, sources=None)[source]

DEPREL counts for arcs like this one, from the most specific level with min_total arcs.

Levels: dependent lemma + head lemma; dependent lemma + head UPOS + direction; dependent UPOS + head UPOS + direction. Use None heads for the root. Counts come from the read-only sources by default.

Parameters:
  • dependent_lemma (str)

  • dependent_upos (str)

  • head_lemma (str | None)

  • head_upos (str | None)

  • direction (Literal['left', 'right', 'root'])

  • min_total (int)

  • sources (list[str] | None)

Return type:

RelationStats

upos_for_function(lemma, deprel, sources=None)[source]

UPOS values used for lemma in relation deprel (subtype ignored); default: read-only sources.

Parameters:
  • lemma (str)

  • deprel (str)

  • sources (list[str] | None)

Return type:

list[ValueCount]

deprels_for_voice(deprel, passive, sources=None)[source]

DEPREL values (with subtype) used for deprel (subtype ignored) on dependents of a passive or active head.

Parameters:
  • deprel (str)

  • passive (bool)

  • sources (list[str] | None)

Return type:

list[ValueCount]

fixed_expressions(source, sent_id, min_count=3, min_share=0.5, sources=None)[source]

Word sequences in a sentence that the trusted data annotates as fixed expressions.

A sequence is reported if it is fixed at least min_count times and in at least min_share of its occurrences.

Parameters:
  • source (str)

  • sent_id (str)

  • min_count (int)

  • min_share (float)

  • sources (list[str] | None)

Return type:

list[FixedExpression]

single_relations(min_heads=20, max_share=0.01, sources=None)[source]

Relations a word almost never has twice (e.g. nsubj), from the trusted data.

Returns {deprel: (words with such a dependent, words with two or more)} for relations seen on at least min_heads words and repeated on at most max_share of them.

Parameters:
  • min_heads (int)

  • max_share (float)

  • sources (list[str] | None)

Return type:

dict[str, tuple[int, int]]

unchained_relations(min_count=100, max_share=0.05, sources=None)[source]

Relations that (almost) never attach to a word with the same relation, from the trusted data.

Returns {deprel: (words with the relation, of which chained)}, e.g. conj attaches to the first conjunct rather than to the previous conj.

Parameters:
  • min_count (int)

  • max_share (float)

  • sources (list[str] | None)

Return type:

dict[str, tuple[int, int]]

xpos_for_tags(upos, feats, sources=None)[source]

XPOS values used with exactly this UPOS and FEATS (default: read-only sources).

Parameters:
  • upos (str)

  • feats (str)

  • sources (list[str] | None)

Return type:

list[ValueCount]

known_values()[source]

XPOS, DEPREL and feature values seen in read-only sources (empty if none).

Return type:

dict[str, set[str]]

validate(source, sent_id=None, limit=50)[source]

Validate one sentence or the whole source; errors are listed before warnings.

Parameters:
  • source (str)

  • sent_id (str | None)

  • limit (int)

Return type:

ValidationReport

low_confidence(source, threshold=0.5, columns=None, sent_id=None, limit=50)[source]

Word cells whose confidence is below threshold, least confident first.

Parameters:
  • source (str)

  • threshold (float)

  • columns (list[str] | None)

  • sent_id (str | None)

  • limit (int)

Return type:

CellPage

get_history(source, sent_id=None, token_id=None, limit=20)[source]

Edits to a source, newest first.

Parameters:
  • source (str)

  • sent_id (str | None)

  • token_id (str | None)

  • limit (int)

Return type:

list[Edit]

update_cells(source, sent_id, updates, agent='agent', dry_run=False)[source]

Apply several cell updates to one sentence, all or nothing.

An update with a value replaces the cell and sets its confidence to confidence (or clears it, falling back to the source default). An update with only confidence re-scores the cell. MISC edits never change Conf. With dry_run the updates are checked and the result (including validation issues) is returned, but nothing is changed.

Parameters:
  • source (str)

  • sent_id (str)

  • updates (list[CellUpdate | dict[str, Any]])

  • agent (str)

  • dry_run (bool)

Return type:

EditResult

score_cells(source, sent_id, scores, reason='', agent='agent', dry_run=False)[source]

Set confidences compactly: {"3:upos": 0.9, "4:*": 0.95}.

"ID:*" (or just "ID") scores every scored column of the word except required columns that are still empty (_), which stay unscored. Specific keys override a wildcard for the same word.

Parameters:
  • source (str)

  • sent_id (str)

  • scores (dict[str, float])

  • reason (str)

  • agent (str)

  • dry_run (bool)

Return type:

EditResult

set_cell(source, sent_id, token_id, column, value, confidence=None, reason='', agent='agent')[source]

Set one cell. See update_cells().

Parameters:
  • source (str)

  • sent_id (str)

  • token_id (str)

  • column (str)

  • value (str)

  • confidence (float | None)

  • reason (str)

  • agent (str)

Return type:

EditResult

split_word(source, sent_id, token_id, forms, multiword=False, head_index=0, confidence=None, reason='', agent='agent', flag_head=True)[source]

Split a word. See mcparser.corpus.segmentation.split_word().

Like the other word-changing edits, this raises a sentence-level flag for the head agent unless flag_head is false.

Parameters:
  • source (str)

  • sent_id (str)

  • token_id (str)

  • forms (list[str])

  • multiword (bool)

  • head_index (int)

  • confidence (float | None)

  • reason (str)

  • agent (str)

  • flag_head (bool)

Return type:

EditResult

merge_words(source, sent_id, token_ids, form=None, confidence=None, reason='', agent='agent')[source]

Merge adjacent words. See mcparser.corpus.segmentation.merge_words().

Parameters:
  • source (str)

  • sent_id (str)

  • token_ids (list[str])

  • form (str | None)

  • confidence (float | None)

  • reason (str)

  • agent (str)

Return type:

EditResult

delete_word(source, sent_id, token_id, reason='', agent='agent')[source]

Delete a word; its dependents move to its head.

Parameters:
  • source (str)

  • sent_id (str)

  • token_id (str)

  • reason (str)

  • agent (str)

Return type:

EditResult

insert_word(source, sent_id, after, form, confidence=None, reason='', agent='agent')[source]

Insert an unannotated word after word after ("0" = at the start).

Parameters:
  • source (str)

  • sent_id (str)

  • after (str)

  • form (str)

  • confidence (float | None)

  • reason (str)

  • agent (str)

Return type:

EditResult

add_multiword(source, sent_id, start, end, form, reason='', agent='agent')[source]

Group words start..``end`` under a multiword surface token.

Parameters:
  • source (str)

  • sent_id (str)

  • start (int)

  • end (int)

  • form (str)

  • reason (str)

  • agent (str)

Return type:

EditResult

remove_multiword(source, sent_id, range_id, reason='', agent='agent')[source]

Remove a multiword token line, keeping its words.

Parameters:
  • source (str)

  • sent_id (str)

  • range_id (str)

  • reason (str)

  • agent (str)

Return type:

EditResult

flag_issue(source, sent_id, column, reason, token_id=None, suggestion=None, agent='agent')[source]

Ask the agent responsible for column to review a word or sentence.

Parameters:
  • source (str)

  • sent_id (str)

  • column (str)

  • reason (str)

  • token_id (str | None)

  • suggestion (str | None)

  • agent (str)

Return type:

Flag

resolve_flag(source, flag_id, status='resolved', note='', agent='agent')[source]

Close a flag as resolved (acted on) or dismissed (no change needed).

Parameters:
  • source (str)

  • flag_id (int)

  • status (Literal['resolved', 'dismissed'])

  • note (str)

  • agent (str)

Return type:

Flag

add_alignment(name, source_a, source_b, path, mode=SourceMode.READ_WRITE, default_confidence=None)[source]

Add word alignments between two loaded sources (sentences paired by sent_id).

Parameters:
  • name (str)

  • source_a (str)

  • source_b (str)

  • path (Path | str)

  • mode (SourceMode | str)

  • default_confidence (float | None)

Return type:

AlignmentInfo

get_parallel(alignment, sent_id)[source]

A sentence pair: both sentences as CoNLL-U, the links, and the words without links.

Parameters:
  • alignment (str)

  • sent_id (str)

Return type:

ParallelView

Set the links of a sentence pair.

links is Ugarit text ("1-1S 2-3P") or a list of links; confidence applies to links that have none. With replace the pair’s links are replaced, otherwise they are added (a link with the same word ids is updated). Word ids must exist in both sentences. Each new or changed link records agent; a link sent again unchanged (same S/P and confidence) keeps the agent that last changed it.

Parameters:
  • alignment (str)

  • sent_id (str)

  • links (str | list[Link | dict[str, Any]])

  • confidence (float | None)

  • replace (bool)

  • reason (str)

  • agent (str)

  • dry_run (bool)

Return type:

ParallelView

Remove links (Ugarit text; S/P suffixes are ignored) from a sentence pair.

Parameters:
  • alignment (str)

  • sent_id (str)

  • links (str)

  • reason (str)

  • agent (str)

Return type:

ParallelView

translation_candidates(lemma, side='a', alignments=None, loose=False, min_confidence=0.0, exclude_sentence=None, limit=10)[source]

What lemma (of source A, or B with side="b") is linked to, over the aligned sentence pairs.

A word’s lemma falls back to its form when the lemma is empty. Only links with at least min_confidence count.

Parameters:
  • lemma (str)

  • side (Literal['a', 'b'])

  • alignments (list[str] | None)

  • loose (bool)

  • min_confidence (float)

  • exclude_sentence (str | None)

  • limit (int)

Return type:

TranslationSearch

Links below threshold, least confident first.

Parameters:
  • alignment (str)

  • threshold (float)

  • sent_id (str | None)

  • limit (int)

Return type:

LinkPage

One CoNLL-U file loaded into memory, read-only or writable.

mcparser.corpus.source.SCORED_COLUMNS = ('form', 'lemma', 'upos', 'xpos', 'feats', 'head', 'deprel')

Columns that count towards a sentence’s confidence (DEPS is optional in UD).

mcparser.corpus.source.REQUIRED_COLUMNS = ('lemma', 'upos', 'head', 'deprel')

Columns where _ means “not annotated yet” (in XPOS, FEATS and DEPS it can be a real value).

class mcparser.corpus.source.SourceMode(*values)[source]

Bases: StrEnum

mcparser.corpus.source.atomic_write(path, text)[source]

Write text to path via a temporary file and an atomic rename.

Parameters:
  • path (Path)

  • text (str)

Return type:

None

class mcparser.corpus.source.CorpusSource(name, path, mode=SourceMode.READ_ONLY, default_confidence=None, root_key='Root')[source]

Bases: object

A CoNLL-U file plus, for writable sources, its review flags and history.

Writable sources keep two sidecar files next to the CoNLL-U file: <file>.review.json (flags) and <file>.history.jsonl (edit log).

Parameters:
  • name (str)

  • path (Path | str)

  • mode (SourceMode | str)

  • default_confidence (float | None)

  • root_key (str)

load()[source]

(Re)load the file and sidecars, discarding unsaved changes.

Return type:

None

changed()[source]

Mark the indexes stale after an edit.

Return type:

None

save()[source]

Write the CoNLL-U file and sidecars.

Raises ConflictError if the file was modified by another process since it was loaded or last saved.

Return type:

None

A small, lossless CoNLL-U model.

Each cell is kept as the raw string from the file so that a read/write round trip never reorders features or rewrites values. Helpers parse FEATS and MISC into dictionaries when structure is needed.

mcparser.corpus.conllu.COLUMNS = ('id', 'form', 'lemma', 'upos', 'xpos', 'feats', 'head', 'deprel', 'deps', 'misc')

The ten CoNLL-U columns in file order.

mcparser.corpus.conllu.EDITABLE_COLUMNS = ('form', 'lemma', 'upos', 'xpos', 'feats', 'head', 'deprel', 'deps', 'misc')

Columns that may be changed with a cell edit (everything except id).

mcparser.corpus.conllu.ANNOTATION_COLUMNS = ('form', 'lemma', 'upos', 'xpos', 'feats', 'head', 'deprel', 'deps')

Columns that carry a confidence score. form stands for segmentation.

mcparser.corpus.conllu.UPOS_TAGS = ('ADJ', 'ADP', 'ADV', 'AUX', 'CCONJ', 'DET', 'INTJ', 'NOUN', 'NUM', 'PART', 'PRON', 'PROPN', 'PUNCT', 'SCONJ', 'SYM', 'VERB', 'X')

The universal part-of-speech tags.

mcparser.corpus.conllu.parse_pairs(value, separator='|')[source]

Parse Key=Value|Key2=Value2 into an ordered dict.

Items without = map to None. _ and the empty string give {}.

Parameters:
  • value (str)

  • separator (str)

Return type:

dict[str, str | None]

mcparser.corpus.conllu.format_pairs(pairs, separator='|')[source]

Inverse of parse_pairs(). An empty dict gives _.

Parameters:
  • pairs (dict[str, str | None])

  • separator (str)

Return type:

str

mcparser.corpus.conllu.format_feats(pairs)[source]

Format FEATS with keys sorted case-insensitively, as UD requires.

Parameters:

pairs (dict[str, str | None])

Return type:

str

mcparser.corpus.conllu.check_cell(column, value)[source]

Validate a cell value for column and return it ("" becomes _).

Parameters:
  • column (str)

  • value (str)

Return type:

str

class mcparser.corpus.conllu.Token(*, id, form='_', lemma='_', upos='_', xpos='_', feats='_', head='_', deprel='_', deps='_', misc='_')[source]

Bases: BaseModel

One CoNLL-U line: a word, a multiword range (3-4) or an empty node (5.1).

Parameters:
  • id (str)

  • form (str)

  • lemma (str)

  • upos (str)

  • xpos (str)

  • feats (str)

  • head (str)

  • deprel (str)

  • deps (str)

  • misc (str)

span()[source]

The (start, end) word ids covered by a multiword token.

Return type:

tuple[int, int]

set_misc_value(key, value)[source]

Set (or with None remove) one MISC attribute, keeping the others.

Parameters:
  • key (str)

  • value (str | None)

Return type:

None

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.conllu.Sentence(*, comments=<factory>, tokens=<factory>)[source]

Bases: BaseModel

A sentence: its comment lines (without the leading #) and its token lines.

Parameters:
  • comments (list[str])

  • tokens (list[Token])

meta(key)[source]

The value of a # key = value comment, if present.

Parameters:

key (str)

Return type:

str | None

property text: str

The # text comment, or the surface forms joined if it is missing.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.corpus.conllu.surface_text(tokens)[source]

Rebuild running text from surface tokens, honouring SpaceAfter=No.

Parameters:

tokens (Iterable[Token])

Return type:

str

mcparser.corpus.conllu.parse_conllu(text)[source]

Parse CoNLL-U text into sentences.

Parameters:

text (str)

Return type:

list[Sentence]

mcparser.corpus.conllu.format_conllu(sentences)[source]

Serialise sentences, each followed by a blank line.

Parameters:

sentences (Iterable[Sentence])

Return type:

str

Per-cell confidence scores stored in the MISC column.

Scores are kept in a single Conf attribute, one column:score pair per annotated column, e.g. Conf=upos:0.95,lemma:0.80,head:0.40. form stands for segmentation. A column without a score falls back to the source’s default confidence (1.0 for read-only training data, 0.0 for predictions).

mcparser.corpus.confidence.read_confidence(token)[source]

The explicit scores on token. Malformed entries are ignored.

Parameters:

token (Token)

Return type:

dict[str, float]

mcparser.corpus.confidence.write_confidence(token, scores)[source]

Replace the scores on token; an empty dict removes Conf.

Parameters:
  • token (Token)

  • scores (dict[str, float])

Return type:

None

mcparser.corpus.confidence.set_confidence(token, column, value)[source]

Set one column’s score, or remove it with None.

Parameters:
  • token (Token)

  • column (str)

  • value (float | None)

Return type:

None

mcparser.corpus.confidence.strip_confidence(misc, original)[source]

Return misc with its Conf replaced by the one in original.

Used when MISC is edited directly so that confidence scores can only be changed through the confidence API.

Parameters:
  • misc (str)

  • original (str)

Return type:

str

Segmentation edits: splitting, merging, inserting and deleting words, and adding or removing multiword tokens.

Every edit works on a _Graph in which HEAD and DEPS point at token objects rather than ids. After the edit the graph is renumbered, so heads, enhanced dependencies, multiword ranges and empty nodes stay consistent.

class mcparser.corpus.segmentation.SegmentationChange(*, id_map, new_ids)[source]

Bases: BaseModel

What a segmentation edit did to the sentence’s token ids.

Parameters:
  • id_map (dict[str, str | None])

  • new_ids (list[str])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.corpus.segmentation.split_word(sentence, token_id, forms, multiword=False, head_index=0)[source]

Replace one word with several.

The piece at head_index keeps the original word’s head, relation, lemma, tags and features, and receives its dependents; the other pieces attach to it with an empty relation. With multiword=True the original surface form is kept as a multiword range (e.g. Arabic clitics); otherwise the word is re-tokenised into separate surface tokens.

Parameters:
  • sentence (Sentence)

  • token_id (str | int)

  • forms (list[str])

  • multiword (bool)

  • head_index (int)

Return type:

SegmentationChange

mcparser.corpus.segmentation.merge_words(sentence, token_ids, form=None)[source]

Merge adjacent words into one.

The merged word takes its annotation from the group’s syntactic head (the first word whose head lies outside the group). If form is omitted it is the surface form of a multiword token that exactly covers the group, or the forms concatenated.

Parameters:
  • sentence (Sentence)

  • token_ids (list[str | int])

  • form (str | None)

Return type:

SegmentationChange

mcparser.corpus.segmentation.delete_word(sentence, token_id)[source]

Delete a word. Its dependents are reattached to its head.

Parameters:
  • sentence (Sentence)

  • token_id (str | int)

Return type:

SegmentationChange

mcparser.corpus.segmentation.insert_word(sentence, after, form)[source]

Insert a new, unannotated word after word after (0 = at the start).

Parameters:
  • sentence (Sentence)

  • after (str | int)

  • form (str)

Return type:

SegmentationChange

mcparser.corpus.segmentation.add_multiword(sentence, start, end, form)[source]

Group words start..``end`` under a multiword token with surface form.

Parameters:
  • sentence (Sentence)

  • start (int)

  • end (int)

  • form (str)

Return type:

SegmentationChange

mcparser.corpus.segmentation.remove_multiword(sentence, range_id)[source]

Remove a multiword token line, keeping its words.

Parameters:
Return type:

SegmentationChange

Structural and tagset checks for a sentence.

class mcparser.corpus.validation.Issue(*, code, severity, message, token_id=None, column=None)[source]

Bases: BaseModel

Parameters:
  • code (str)

  • severity (Literal['error', 'warning'])

  • message (str)

  • token_id (str | None)

  • column (str | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.corpus.validation.validate_sentence(sentence, known=None)[source]

Check ids, ranges, tags, features and the dependency tree.

known maps a column (xpos, deprel, feats) to the values seen in trusted data; values outside it give an unseen-value warning. For feats the set holds individual Feature=Value pairs.

Parameters:
  • sentence (Sentence)

  • known (dict[str, set[str]] | None)

Return type:

list[Issue]

Word alignments between two sources (e.g. a translation and its original).

An alignment set pairs sentences with the same sent_id in two sources and holds word links between them. Links are written in the Ugarit style 1-3S 2-5P (word id in source A, word id in source B, S = sure, P = probable); many-to-many alignments are several links. Each link may carry a confidence, as cells do.

Sets are stored as JSON Lines, one line per sentence pair:

{"sent_id": "B10K1V1", "links": [{"source": "1", "target": "1", "sure": true, "confidence": 0.95}]}

Like sources, a set is read-only (trusted, e.g. gold alignments) or writable, edits are saved immediately, and every change is recorded in a <file>.history.jsonl sidecar.

Bases: BaseModel

Parameters:
  • source (str)

  • target (str)

  • sure (bool)

  • confidence (Annotated[float | None, Ge(ge=0.0), Le(le=1.0)])

  • agent (str | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.corpus.alignment.parse_ugarit(text, confidence=None)[source]

Parse "1-3S 2-5P 4-4" (no suffix means sure) into links.

Parameters:
  • text (str)

  • confidence (float | None)

Return type:

list[Link]

class mcparser.corpus.alignment.AlignmentInfo(*, name, source_a, source_b, path, mode, default_confidence, sentences, links)[source]

Bases: BaseModel

Parameters:
  • name (str)

  • source_a (str)

  • source_b (str)

  • path (str)

  • mode (str)

  • default_confidence (float)

  • sentences (int)

  • links (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.alignment.AlignmentSet(name, source_a, source_b, path, mode=SourceMode.READ_WRITE, default_confidence=None)[source]

Bases: object

Links between the sentences of two sources, persisted as JSON Lines.

Parameters:
load()[source]

(Re)load the file; a missing writable file starts empty and is created on first save.

Return type:

None

In-memory indexes over one source’s sentences.

Lookups are by exact string or by a loose key (Unicode NFD with combining marks removed, case-folded), which lets unvocalised or unaccented forms match annotated ones. Sentence search uses BM25 over loose word tokens.

mcparser.corpus.index.loose(text)[source]

Case-fold and strip combining marks (accents, vowel points, breathings).

Parameters:

text (str)

Return type:

str

mcparser.corpus.index.Location

(sentence position, token position) within a source.

alias of tuple[int, int]

mcparser.corpus.index.SUFFIX_LENGTHS = (3, 4, 5)

Lengths of the (loose) word endings that are indexed, for analogy with unseen forms.

class mcparser.corpus.index.SourceIndex(sentences, root_key='Root', bm25_k1=1.5, bm25_b=0.75)[source]

Bases: object

Postings and tag inventories for one list of sentences.

Parameters:
  • sentences (list[Sentence])

  • root_key (str)

  • bm25_k1 (float)

  • bm25_b (float)

by_case: defaultdict[tuple[str, str, str, str], Counter[str]]

Feature value counts for each (UPOS, Case, Number, feature), to see where combined values (Masc,Neut) are used.

xpos_by_tags: defaultdict[tuple[str, str], Counter[str]]

XPOS counts for each (UPOS, FEATS) pair.

upos_by_function: defaultdict[tuple[str, str], Counter[str]]

UPOS counts for each (LEMMA, DEPREL without subtype) pair.

fixed: Counter[tuple[str, ...]]

a head and its fixed dependents.

Type:

Word sequences (loose forms) annotated as fixed expressions

fixed_occurrences: Counter[tuple[str, ...]]

How often each of those sequences occurs at all (fixed or not).

dependents: Counter[str]

Per DEPREL, the number of words with at least one dependent of that relation.

by_voice: defaultdict[tuple[str, bool], Counter[str]]

pass).

Type:

Per (DEPREL without subtype, whether the head is passive), the full DEPREL values (nsubj vs nsubj

chained: Counter[str]

Per DEPREL, the number of words whose head has the same DEPREL (e.g. conj attached to a conj).

suffix(ending)[source]

Words whose loose form ends with ending; None if that length is not indexed.

Parameters:

ending (str)

Return type:

list[tuple[int, int]] | None

search(query)[source]

BM25-ranked (sentence position, score) pairs with a positive score.

Parameters:

query (str)

Return type:

list[tuple[int, float]]

mcparser.corpus.index.direction_of(token_id, head_id)[source]

Side of the dependent on which its head lies: left, right or root.

Parameters:
  • token_id (str)

  • head_id (str)

Return type:

str

mcparser.corpus.index.relation_keys(dep_lemma, dep_upos, head_lemma, head_upos, direction)[source]

Keys for relation statistics, most specific first.

head_lemma/head_upos are None for the root. The levels are (dependent lemma, head lemma), (dependent lemma, head UPOS, direction) and (dependent UPOS, head UPOS, direction).

Parameters:
  • dep_lemma (str)

  • dep_upos (str)

  • head_lemma (str | None)

  • head_upos (str | None)

  • direction (str)

Return type:

list[tuple[str, …]]

Unannotated text as evidence: how often a word occurs, next to which words, in which sentences.

Raw text has no analyses, so it cannot say what a word is, but it shows how the word is used: its frequency, its neighbours, whether longer words contain it (a stem with a clitic) and what it looks like in running text. That is useful for forms the treebank has never seen. A corpus can be tens of millions of words, so only counts and a few line numbers per word are kept in memory; the sentences are read from the files when an example is wanted.

mcparser.corpus.textcorpus.WORD = re.compile('[\\ẁ-֑ͯ-ׇؐ-ًؚ-ٰٟۖ-ۭ]+')

Letters and digits plus the combining marks of Latin/Greek, Hebrew and Arabic (vowels, accents).

mcparser.corpus.textcorpus.POSTINGS_MAX = 50

enough for examples and neighbour counts, small enough for 25 million words.

Type:

Line numbers kept per word

mcparser.corpus.textcorpus.AFFIX_MINIMUM = 3

Words shorter than this are not searched for inside longer words.

mcparser.corpus.textcorpus.AFFIX_EXTRA = 4

Longer words are at most this many letters longer (clitics are short; longer ones are mostly run-together text).

mcparser.corpus.textcorpus.FILE_BITS = 40

A line is addressed as file_number << FILE_BITS | byte_offset.

class mcparser.corpus.textcorpus.TextCorpus(name, paths)[source]

Bases: object

One or more plain-text files, one sentence or paragraph per line.

The index is built the first time it is needed (about 10 seconds for 25 million words) and is safe to share between threads. Words are runs of letters, digits and combining marks, so punctuation is ignored.

Parameters:
  • name (str)

  • paths (list[Path | str])

build()[source]

Read the files and count the words (done once, on first use).

Return type:

None

count(form, loose=False)[source]

Occurrences of form (with loose, ignoring case and diacritics).

Parameters:
  • form (str)

  • loose (bool)

Return type:

int

find(form, loose=False, examples=3, width=6, neighbours=5, affixed=5)[source]

Counts, neighbours, longer words containing form and example lines (width words each side).

Parameters:
  • form (str)

  • loose (bool)

  • examples (int)

  • width (int)

  • neighbours (int)

  • affixed (int)

Return type:

CorpusSearch

Pydantic models returned by the corpus store (and hence by the MCP tools).

class mcparser.corpus.models.Flag(*, id, sent_id, token_id=None, column, reason, suggestion=None, raised_by, status='open', resolved_by=None, note=None, created, round=None)[source]

Bases: BaseModel

A request for the agent responsible for column to review a cell or sentence.

Parameters:
  • id (int)

  • sent_id (str)

  • token_id (str | None)

  • column (str)

  • reason (str)

  • suggestion (str | None)

  • raised_by (str)

  • status (Literal['open', 'resolved', 'dismissed'])

  • resolved_by (str | None)

  • note (str | None)

  • created (str)

  • round (int | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.Edit(*, seq, time, sent_id, token_id=None, action, column=None, old=None, new=None, confidence=None, reason='', agent, round=None)[source]

Bases: BaseModel

One entry in a source’s edit history.

Parameters:
  • seq (int)

  • time (str)

  • sent_id (str)

  • token_id (str | None)

  • action (str)

  • column (str | None)

  • old (str | None)

  • new (str | None)

  • confidence (float | None)

  • reason (str)

  • agent (str)

  • round (int | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.SourceInfo(*, name, path, mode, default_confidence, sentences, words, open_flags)[source]

Bases: BaseModel

Parameters:
  • name (str)

  • path (str)

  • mode (Literal['ro', 'rw'])

  • default_confidence (float)

  • sentences (int)

  • words (int)

  • open_flags (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.SentenceSummary(*, source, sent_id, position, text, words, confidence, open_flags)[source]

Bases: BaseModel

Parameters:
  • source (str)

  • sent_id (str)

  • position (int)

  • text (str)

  • words (int)

  • confidence (float)

  • open_flags (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.SentencePage(*, total, sentences)[source]

Bases: BaseModel

Parameters:
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.SentenceView(*, source, sent_id, position, text, conllu, tokens=None, confidence, open_flags, issues)[source]

Bases: BaseModel

Parameters:
  • source (str)

  • sent_id (str)

  • position (int)

  • text (str)

  • conllu (str)

  • tokens (list[Token] | None)

  • confidence (float)

  • open_flags (list[Flag])

  • issues (list[Issue])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.TokenRef(*, id, form, lemma, upos, deprel)[source]

Bases: BaseModel

Parameters:
  • id (str)

  • form (str)

  • lemma (str)

  • upos (str)

  • deprel (str)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.TokenView(*, source, sent_id, token, confidence, head=None, dependents, multiword=None)[source]

Bases: BaseModel

Parameters:
  • source (str)

  • sent_id (str)

  • token (Token)

  • confidence (dict[str, float])

  • head (TokenRef | None)

  • dependents (list[TokenRef])

  • multiword (TokenRef | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.TokenHit(*, source, sent_id, token_id, form, lemma, upos, xpos, feats, head, deprel, misc, head_form=None, confidence, context)[source]

Bases: BaseModel

Parameters:
  • source (str)

  • sent_id (str)

  • token_id (str)

  • form (str)

  • lemma (str)

  • upos (str)

  • xpos (str)

  • feats (str)

  • head (str)

  • deprel (str)

  • misc (str)

  • head_form (str | None)

  • confidence (float)

  • context (str)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.GroupCount(*, values, count)[source]

Bases: BaseModel

Parameters:
  • values (dict[str, str])

  • count (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.TokenSearch(*, total, groups, hits)[source]

Bases: BaseModel

Parameters:
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.SentenceHit(*, source, sent_id, text, score, confidence)[source]

Bases: BaseModel

Parameters:
  • source (str)

  • sent_id (str)

  • text (str)

  • score (float)

  • confidence (float)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.MultiwordAnalysis(*, pieces, upos, count, examples)[source]

Bases: BaseModel

Parameters:
  • pieces (list[str])

  • upos (list[str])

  • count (int)

  • examples (list[str])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.MultiwordSearch(*, surface, total, analyses, as_single_word)[source]

Bases: BaseModel

Parameters:
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.ArcHit(*, source, sent_id, dependent, head, deprel, direction, distance, confidence, context)[source]

Bases: BaseModel

Parameters:
  • source (str)

  • sent_id (str)

  • dependent (TokenRef)

  • head (TokenRef | None)

  • deprel (str)

  • direction (Literal['left', 'right', 'root'])

  • distance (int)

  • confidence (float)

  • context (str)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.ValueCount(*, value, count)[source]

Bases: BaseModel

Parameters:
  • value (str)

  • count (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.FeatureConvention(*, upos, case, number, feature, values)[source]

Bases: BaseModel

How a feature is written with a UPOS, Case and Number, where the treebank uses combined values (Masc,Neut).

Parameters:
  • upos (str)

  • case (str)

  • number (str)

  • feature (str)

  • values (list[ValueCount])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.CorpusInfo(*, name, files, lines, words, types)[source]

Bases: BaseModel

An unannotated text corpus (see TextCorpus).

Parameters:
  • name (str)

  • files (list[str])

  • lines (int)

  • words (int)

  • types (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.CorpusExample(*, file, line, before, form, after)[source]

Bases: BaseModel

One occurrence of a word in an unannotated corpus, with the words around it.

Parameters:
  • file (str)

  • line (int)

  • before (str)

  • form (str)

  • after (str)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.CorpusSearch(*, corpus, form, total, forms, previous, next, sample, prefixed, suffixed, examples)[source]

Bases: BaseModel

How a word is used in an unannotated corpus: counts, neighbours, longer words containing it, examples.

Parameters:
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.FixedExpression(*, start, end, forms, fixed, occurrences)[source]

Bases: BaseModel

A word sequence of a sentence that the trusted data annotates as a fixed expression.

Parameters:
  • start (str)

  • end (str)

  • forms (list[str])

  • fixed (int)

  • occurrences (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.RelationStats(*, basis, total, deprels)[source]

Bases: BaseModel

How the trusted data labels arcs like a given one.

Parameters:
  • basis (str)

  • total (int)

  • deprels (list[ValueCount])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.ArcSearch(*, total, deprels, directions, hits)[source]

Bases: BaseModel

Parameters:
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.CellRef(*, sent_id, token_id, form, column, value, confidence)[source]

Bases: BaseModel

Parameters:
  • sent_id (str)

  • token_id (str)

  • form (str)

  • column (str)

  • value (str)

  • confidence (float)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.CellPage(*, total, cells)[source]

Bases: BaseModel

Parameters:
  • total (int)

  • cells (list[CellRef])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.FlagPage(*, total, flags)[source]

Bases: BaseModel

Parameters:
  • total (int)

  • flags (list[Flag])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.SentenceIssue(*, sent_id, issue)[source]

Bases: BaseModel

Parameters:
  • sent_id (str)

  • issue (Issue)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.ValidationReport(*, total, errors, warnings, issues)[source]

Bases: BaseModel

Parameters:
  • total (int)

  • errors (int)

  • warnings (int)

  • issues (list[SentenceIssue])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.ParallelView(*, alignment, sent_id, source_a, source_b, conllu_a, conllu_b, links, confidence, agents=<factory>, unaligned_a, unaligned_b)[source]

Bases: BaseModel

A sentence pair of an alignment set, with its links.

Parameters:
  • alignment (str)

  • sent_id (str)

  • source_a (str)

  • source_b (str)

  • conllu_a (str)

  • conllu_b (str)

  • links (str)

  • confidence (dict[str, float])

  • agents (dict[str, str])

  • unaligned_a (list[str])

  • unaligned_b (list[str])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.TranslationSearch(*, lemma, side, occurrences, unaligned, candidates, examples)[source]

Bases: BaseModel

What a lemma is aligned to in the other source.

Parameters:
  • lemma (str)

  • side (str)

  • occurrences (int)

  • unaligned (int)

  • candidates (list[ValueCount])

  • examples (list[str])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.LinkRef(*, alignment, sent_id, link, form_a, form_b, confidence)[source]

Bases: BaseModel

Parameters:
  • alignment (str)

  • sent_id (str)

  • link (str)

  • form_a (str)

  • form_b (str)

  • confidence (float)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.LinkPage(*, total, links)[source]

Bases: BaseModel

Parameters:
  • total (int)

  • links (list[LinkRef])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.CellUpdate(*, token_id, column, value=None, confidence=None, reason='')[source]

Bases: BaseModel

A change to one cell: a new value, a new confidence, or both.

Parameters:
  • token_id (str)

  • column (str)

  • value (str | None)

  • confidence (Annotated[float | None, Ge(ge=0.0), Le(le=1.0)])

  • reason (str)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.corpus.models.EditResult(*, source, sent_id, edits, conllu, issues, id_map=None, new_ids=None)[source]

Bases: BaseModel

Parameters:
  • source (str)

  • sent_id (str)

  • edits (list[Edit])

  • conllu (str)

  • issues (list[Issue])

  • id_map (dict[str, str | None] | None)

  • new_ids (list[str] | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

Exceptions raised by the corpus layer.

Every exception derives from CorpusError so that callers (e.g. the MCP server) can turn any expected failure into a message for the model.

exception mcparser.corpus.errors.CorpusError[source]

Bases: Exception

Base class for all expected corpus failures.

exception mcparser.corpus.errors.ConlluFormatError[source]

Bases: CorpusError

The CoNLL-U text could not be parsed.

exception mcparser.corpus.errors.NotFoundError[source]

Bases: CorpusError

A source, sentence, token or flag does not exist.

exception mcparser.corpus.errors.ReadOnlyError[source]

Bases: CorpusError

An edit was attempted on a read-only source.

exception mcparser.corpus.errors.ConflictError[source]

Bases: CorpusError

The file on disk changed since it was loaded.

exception mcparser.corpus.errors.EditError[source]

Bases: CorpusError

An edit was rejected because its arguments are invalid.

MCP server

MCP server exposing a CorpusStore.

The same server is used by the mcparser agents (in-process or over stdio), by Claude Desktop, and by other projects such as llmaligner.

mcparser.mcp.server.build_server(store, name='conllu', allow_edits=True, log_level='WARNING')[source]

Create an MCP server over store.

With allow_edits=False only the read-only tools are registered, which is useful for exploring a corpus from Claude Desktop without risk. The MCP SDK configures the root logger at log_level; the WARNING default keeps per-request logs out of the terminal.

Parameters:
  • store (CorpusStore)

  • name (str)

  • allow_edits (bool)

  • log_level (Literal['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'])

Return type:

MCPServer

Source specifications and client configuration for the MCP server.

mcparser.mcp.config.split_file_spec(text, spec)[source]

PATH[:MODE[:CONFIDENCE]] as (resolved path, mode or None, confidence or None).

Parameters:
  • text (str)

  • spec (str)

Return type:

tuple[Path, SourceMode | None, float | None]

class mcparser.mcp.config.SourceSpec(*, name, path, mode=SourceMode.READ_ONLY, default_confidence=None)[source]

Bases: BaseModel

A source given on the command line as [NAME=]PATH[:MODE[:CONFIDENCE]].

MODE is ro (default) or rw. CONFIDENCE is the default confidence for cells without a Conf score. NAME defaults to the file stem. Examples: train.conllu, pred=out/pred.conllu:rw, silver=silver.conllu:ro:0.8.

Parameters:
  • name (str)

  • path (Path)

  • mode (SourceMode)

  • default_confidence (float | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.mcp.config.AlignmentSpec(*, name, source_a, source_b, path, mode=SourceMode.READ_WRITE, default_confidence=None)[source]

Bases: BaseModel

An alignment set given as NAME=SOURCE_A,SOURCE_B,PATH[:ro|rw[:CONFIDENCE]].

SOURCE_A and SOURCE_B are names of --source sources. The mode defaults to rw; a writable file that does not exist yet is created. Example: verses=arabic,greek,alignments.jsonl.

Parameters:
  • name (str)

  • source_a (str)

  • source_b (str)

  • path (Path)

  • mode (SourceMode)

  • default_confidence (float | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.mcp.config.CorpusSpec(*, name, paths)[source]

Bases: BaseModel

An unannotated text corpus given as [NAME=]PATH[,PATH...].

The files hold plain text, one sentence or paragraph per line. NAME defaults to the stem of the first file. Example: arabic=train.txt,valid.txt.

Parameters:
  • name (str)

  • paths (list[Path])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.mcp.config.claude_desktop_config(specs, name='conllu', read_only=False, root_key='Root', alignments=None, corpora=None)[source]

The mcpServers entry for Claude Desktop’s claude_desktop_config.json.

Parameters:
Return type:

dict[str, Any]

Agents and pipeline

The agent roles: one per annotated CoNLL-U column, plus the scorer.

mcparser.agents.roles.READ_TOOLS = frozenset({'allowed_values', 'analyse_form', 'feature_inventory', 'find_arcs', 'find_multiword', 'find_tokens', 'get_context', 'get_sentence', 'list_flags', 'relation_stats', 'search_sentences', 'validate'})

MCP tools every agent may use.

Deliberately smaller than the server’s full set: the task prompt already gives the sentence, the cells to work on, open flags and the main evidence, so tools such as list_sources, get_token or low_confidence would only add tokens to every request.

mcparser.agents.roles.CORPUS_TOOLS = frozenset({'corpus_find'})

Added to every role’s tools when there is a text corpus and the corpus_tool setting is on.

class mcparser.agents.roles.Role(name: 'str', title: 'str', columns: 'tuple[str, ...]')[source]

Bases: object

Parameters:
  • name (str)

  • title (str)

  • columns (tuple[str, ...])

columns: tuple[str, ...]

Columns this role may change (and whose flags it handles).

property column: str

The column whose low-confidence cells and flags this role handles.

property edits_with_tools: bool

Segmentation edits through tools (it renumbers words); the other roles return compact answers.

mcparser.agents.roles.REFINE_ORDER = ('segmentation', 'upos', 'lemma', 'syntax', 'head', 'deprel', 'feats', 'xpos', 'deps')

later columns build on earlier ones. Syntax comes before FEATS because case and definiteness depend on a word’s function, and XPOS comes last because in many treebanks it encodes UPOS and FEATS.

Type:

Order in which roles work

mcparser.agents.roles.DEFAULT_DISABLED = frozenset({'deps'})

Roles that only run when enabled in the settings (enhanced dependencies are optional in UD).

mcparser.agents.roles.SEPARATE_SYNTAX_ROLES = frozenset({'deprel', 'head'})

By default one syntax agent sets HEAD and DEPREL together (setting joint_syntax); with joint_syntax: false the head and deprel agents do it one after the other.

The pydantic-ai agents, one per role, sharing one MCP connection.

class mcparser.agents.team.TaskReport(*, summary)[source]

Bases: BaseModel

What an agent that edits through tools returns when it finishes a task.

Parameters:

summary (str)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.agents.team.ModelUsage(*, tasks=0, requests=0, input_tokens=0, cache_read_tokens=0, cache_write_tokens=0, output_tokens=0, cost=None)[source]

Bases: BaseModel

Token use of one model over a run.

Parameters:
  • tasks (int)

  • requests (int)

  • input_tokens (int)

  • cache_read_tokens (int)

  • cache_write_tokens (int)

  • output_tokens (int)

  • cost (float | None)

merge(other)[source]

Add another usage (e.g. of a different model); cost is None if either has no price.

Parameters:

other (ModelUsage)

Return type:

None

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.agents.team.AgentTeam(store, target, settings, models=None, toolset=None)[source]

Bases: object

Builds and runs the role agents.

By default the agents reach the corpus through an in-process MCP server over store; pass toolset to use another MCP connection (e.g. a MCPToolset for a remote server). models maps a role name (or "*" for all roles) to a model name or instance, overriding the settings; tests use it to supply scripted models.

Parameters:
  • store (CorpusStore)

  • target (str)

  • settings (Settings)

  • models (Mapping[str, Model | str] | None)

  • toolset (AbstractToolset[Any] | None)

usage: dict[str, ModelUsage]

Token use and estimated cost per model.

role_usage: dict[str, ModelUsage]

Token use and estimated cost per role.

relations()[source]

The trusted DEPREL inventory as one line, for the syntax roles’ instructions.

Return type:

str

async run(role, prompt, batch, usage=None, retries=None)[source]

Run role on a task; for compact answers, the edits are applied when the answer is accepted.

The task’s token use is added to the per-model and per-role totals and, if given, to usage; the retry messages sent to the model (why a request was repeated) are appended to retries.

Parameters:
  • role (str)

  • prompt (str)

  • batch (Batch)

  • usage (ModelUsage | None)

  • retries (list[str] | None)

Return type:

TaskReport | Annotation | Scores

total()[source]

Usage summed over all models (cost is None if any model has no price).

Return type:

ModelUsage

Restrict the MCP tools an agent sees and what it may write.

class mcparser.agents.toolset.RoleToolset(wrapped, role, target, extra=frozenset({}))[source]

Bases: WrapperToolset[Any]

The MCP toolset as seen by one role.

Only the role’s tools are listed, and results come back as compact text (see mcparser.agents.compact). The agent argument is hidden from the model and filled in with the role name, so edits and flags are attributed correctly. Writes are limited to the target source and the role’s columns; the scorer may only send confidences. A refused call is returned to the model as a retry prompt explaining why.

Parameters:
  • wrapped (AbstractToolset[AgentDepsT])

  • role (Role)

  • target (str)

  • extra (frozenset[str])

extra: frozenset[str] = frozenset({})

Tools every role may use besides its own (the corpus tool).

async get_tools(ctx)[source]

The tools that are available in this toolset.

Parameters:

ctx (RunContext[Any])

Return type:

dict[str, ToolsetTool[Any]]

check(name, args)[source]

Raise ModelRetry if the role may not make this call.

Parameters:
  • name (str)

  • args (dict[str, Any])

Return type:

None

static normalise(name, args)[source]

Accept updates sent as a JSON string, as models sometimes do.

Parameters:
  • name (str)

  • args (dict[str, Any])

Return type:

dict[str, Any]

async call_tool(name, tool_args, ctx, tool)[source]

Call a tool with the given arguments.

Parameters:
  • name (str) – The name of the tool to call.

  • tool_args (dict[str, Any]) – The arguments to pass to the tool.

  • ctx (RunContext[Any]) – The run context.

  • tool (ToolsetTool[Any]) – The tool definition returned by [get_tools][pydantic_ai.toolsets.AbstractToolset.get_tools] that was called.

Return type:

Any

Instructions and task prompts for the agents.

class mcparser.agents.prompts.TaskItem(sent_id, cells, flags=<factory>, conllu='')[source]

Bases: object

One sentence of a task: its CoNLL-U, the cells to work on and open flags.

Parameters:
  • sent_id (str)

  • cells (list[CellRef])

  • flags (list[Flag])

  • conllu (str)

mcparser.agents.prompts.sentence_block(conllu)[source]

CoNLL-U without the Conf attributes (the cells to work on list confidences) and trailing empty columns.

Parameters:

conllu (str)

Return type:

str

mcparser.agents.prompts.task_prompt(role, target, items, evidence='')[source]

The user prompt for one role working on a batch of sentences.

Parameters:
  • role (Role)

  • target (str)

  • items (list[TaskItem])

  • evidence (str)

Return type:

str

The rules → score → refine loop over a prediction source.

Before the first round, code settles what it can (see mcparser.rules), including columns the trusted data never uses. Then each round:

  1. Score. The scorer rates cells that a model or a person changed since it last scored them. Cells set by code are not re-checked: their confidence is based on the evidence.

  2. Refine. Each role in REFINE_ORDER works on cells of its column below the threshold and on flags raised for it. Sentences go from most to least confident, in batches of several sentences per task. After each role, the rules run again on the sentences it touched (e.g. XPOS from the new UPOS and FEATS, DEPREL for the new heads).

Rounds repeat until nothing is left to refine, a round changes nothing, or the round limit is reached. A final scoring pass then re-scores the last changes.

mcparser.pipeline.EDIT_ACTIONS = frozenset({'add_multiword', 'delete_word', 'insert_word', 'merge_words', 'remove_multiword', 'set', 'split_word'})

History actions that change annotation (as opposed to confidences and flags).

class mcparser.pipeline.TaskResult(*, round, sent_ids, role, summary=None, error=None, usage=None, retries=[])[source]

Bases: BaseModel

Parameters:
  • round (int)

  • sent_ids (list[str])

  • role (str)

  • summary (str | None)

  • error (str | None)

  • usage (ModelUsage | None)

  • retries (list[str])

retries: list[str]

Why the model had to answer again (invalid values, broken trees, doubled relations).

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.pipeline.RoundReport(*, round, scored, tasks, edits, open_flags, confidence)[source]

Bases: BaseModel

Parameters:
  • round (int)

  • scored (int)

  • tasks (int)

  • edits (int)

  • open_flags (int)

  • confidence (float)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.pipeline.RunReport(*, rounds, final_scored=0, confidence, rules, tasks, total, usage, roles={}, budget_reached=False)[source]

Bases: BaseModel

Parameters:
roles: dict[str, ModelUsage]

Token use and estimated cost per role.

budget_reached: bool

The run stopped early because max_cost was reached; tasks that were not started are recorded as skipped.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.pipeline.Pipeline(store, target, team, settings, sent_ids=None, progress=None)[source]

Bases: object

Runs the rules → score → refine rounds over one writable source.

sent_ids restricts the work to some sentences; progress receives a line of text after every agent task and round.

Parameters:
confidence()[source]

Mean confidence over the cells of the enabled roles’ columns.

Return type:

float

history_state()[source]

For each sentence, when (and by whom) each cell was last changed, and when it was last scored.

Return type:

dict[str, _CellHistory]

cells_to_score(sent_id, state=None)[source]

Cells that a model or person changed since the scorer last saw them.

Skipped: cells whose last change came from code (rules or the baseline), required cells that are still empty (_ LEMMA, UPOS, HEAD, DEPREL), and XPOS and FEATS of words without a UPOS, which cannot be judged yet.

Parameters:
  • sent_id (str)

  • state (dict[str, _CellHistory] | None)

Return type:

list[CellRef]

edits_since(seq)[source]

Edits by agents or people (not rules) after history entry seq.

Parameters:

seq (int)

Return type:

int

batches(items)[source]

Group items into tasks of at most batch_sentences sentences and batch_cells words with cells.

Parameters:

items (list[TaskItem])

Return type:

list[list[TaskItem]]

async score()[source]

Score the cells that need it. Returns the number of sentences scored (none if the scorer is disabled).

Return type:

int

async refine()[source]

Run each role on low-confidence cells and open flags. Returns the number of tasks.

Return type:

int

settle_unused_columns()[source]

Settle XPOS/FEATS by rule when the trusted data never uses them.

Some treebanks leave XPOS (or FEATS) empty throughout. Then _ is the only right value, so it is set with confidence 1.0 and the role is not run, which saves a model task per sentence. Returns the settled columns.

Return type:

list[str]

async run(rounds=None, score_only=False)[source]

Apply the rules and run up to rounds rounds (default from the settings).

A final scoring pass of the cells changed in the last round follows if settings.final_scoring is on. It costs a scorer task per changed sentence but changes no annotation, so it is off by default. With score_only only the rules and the scorer run, once.

Parameters:
  • rounds (int | None)

  • score_only (bool)

Return type:

RunReport

Run settings: which model each agent uses, thresholds and rounds.

Roles run on one of three model tiers: a strong model for the hard judgements (segmentation, lemmas, syntax), an efficient model for roles that mostly apply the evidence (UPOS, FEATS, scoring), and a light model for lookups (XPOS). Settings can be loaded from YAML, e.g.:

strong_model: anthropic:claude-opus-5-5
efficient_model: anthropic:claude-sonnet-5-5
light_model: anthropic:claude-haiku-5-5
efficient_roles: [upos, feats, scorer]
light_roles: [xpos]
strong_thinking: low          # reasoning effort; omit for the model's default
batch_sentences: 8            # sentences per agent task
rules:
  min_count: 5                # examples needed before code settles a cell
  min_share: 0.95
threshold: 0.8
rounds: 3
roles:
  head:
    thinking: medium
  deps:
    enabled: true
  lemma:
    model: anthropic:claude-opus-5-5
    instructions: Write Sumerograms as their Hittite reading when known.
mcparser.settings.DEFAULT_EFFICIENT_ROLES = ('upos', 'feats', 'scorer')

Roles that mostly apply the evidence given in their prompt.

mcparser.settings.DEFAULT_LIGHT_ROLES = ('xpos',)

Roles that are close to a lookup once UPOS and FEATS are known.

mcparser.settings.Thinking

False (off), True (provider default) or a level.

Type:

Reasoning effort

alias of bool | Literal[‘minimal’, ‘low’, ‘medium’, ‘high’, ‘xhigh’]

mcparser.settings.parse_thinking(value)[source]

Parse a command-line thinking value: off, on, or a level.

Parameters:

value (str)

Return type:

bool | Literal[‘minimal’, ‘low’, ‘medium’, ‘high’, ‘xhigh’]

class mcparser.settings.RoleSettings(*, model=None, thinking=None, enabled=None, instructions=None)[source]

Bases: BaseModel

Parameters:
  • model (str | None)

  • thinking (bool | Literal['minimal', 'low', 'medium', 'high', 'xhigh'] | None)

  • enabled (bool | None)

  • instructions (str | None)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.settings.Settings(*, strong_model='anthropic:claude-opus-5-5', efficient_model='anthropic:claude-sonnet-5-5', light_model='anthropic:claude-haiku-5-5', efficient_roles=['upos', 'feats', 'scorer'], light_roles=['xpos'], strong_thinking=None, efficient_thinking=None, light_thinking=None, model=None, threshold=0.8, rounds=3, concurrency=1, request_limit=60, cache=True, batch_sentences=8, batch_cells=120, joint_syntax=True, final_scoring=False, max_cost=None, corpus_tool=True, conventions=True, rules=<factory>, roles=<factory>)[source]

Bases: BaseModel

Parameters:
  • strong_model (str)

  • efficient_model (str)

  • light_model (str)

  • efficient_roles (list[str])

  • light_roles (list[str])

  • strong_thinking (bool | Literal['minimal', 'low', 'medium', 'high', 'xhigh'] | None)

  • efficient_thinking (bool | Literal['minimal', 'low', 'medium', 'high', 'xhigh'] | None)

  • light_thinking (bool | Literal['minimal', 'low', 'medium', 'high', 'xhigh'] | None)

  • model (str | None)

  • threshold (Annotated[float, Ge(ge=0), Le(le=1)])

  • rounds (Annotated[int, Ge(ge=1)])

  • concurrency (Annotated[int, Ge(ge=1)])

  • request_limit (Annotated[int, Ge(ge=1)])

  • cache (bool)

  • batch_sentences (Annotated[int, Ge(ge=1)])

  • batch_cells (Annotated[int, Ge(ge=1)])

  • joint_syntax (bool)

  • final_scoring (bool)

  • max_cost (Annotated[float | None, Gt(gt=0)])

  • corpus_tool (bool)

  • conventions (bool)

  • rules (RuleSettings)

  • roles (dict[str, RoleSettings])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

with_overrides(model=None, role_models=None, only_roles=None, **fields)[source]

A copy with command-line overrides applied (None values are ignored).

Parameters:
  • model (str | None)

  • role_models (dict[str, str] | None)

  • only_roles (list[str] | None)

  • fields (object)

Return type:

Settings

A frequency baseline that needs no LLM.

For each surface token it applies the most frequent multiword split seen in the trusted sources, and for each word it copies the most frequent (LEMMA, UPOS, XPOS, FEATS) analysis of the same form. Only empty cells (_ with no confidence recorded) are filled, so running it twice changes nothing. The confidence reflects how much evidence there was, so the scorer and the role agents know where to look first. HEAD and DEPREL are left to the agents.

class mcparser.baseline.BaselineReport(*, sentences=0, splits=0, analysed=0, unknown=0)[source]

Bases: BaseModel

Parameters:
  • sentences (int)

  • splits (int)

  • analysed (int)

  • unknown (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.baseline.BASELINE_MAX_CONFIDENCE = 0.7

a most-frequent analysis is only a candidate, so an agent always reviews it. Near-certain cells are settled by mcparser.rules instead (at 0.97).

Type:

Below the default refinement threshold

mcparser.baseline.evidence_confidence(count, total)[source]

Agreement among the examples, discounted when there are few (at most 0.7).

Parameters:
  • count (int)

  • total (int)

Return type:

float

Turn raw text into an unannotated CoNLL-U file.

Three input formats are accepted:

  • plain text, one sentence per line (sentence ids are the line numbers of the non-empty lines);

  • YAML mapping ids to entries with a text field, as in ArabGr1-Ephesians-Parsed.yaml. Other scalar fields (e.g. verse) become comments; a conllu field is ignored. A YAML list of such entries (with sent_id or id) or of plain strings also works;

  • CoNLL-U (e.g. a gold test set): the segmentation and comments are kept and all annotation is removed (see blank_sentences()), which gives a fair held-out test with gold tokenisation.

class mcparser.textinput.InputSentence(*, sent_id, text, meta=<factory>)[source]

Bases: BaseModel

Parameters:
  • sent_id (str)

  • text (str)

  • meta (dict[str, str])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.textinput.tokenise(text)[source]

Split on whitespace and detach leading/trailing punctuation.

Returns (form, space_after) pairs. Punctuation inside a word (don't, U.S) is kept, and combining marks are never split off.

Parameters:

text (str)

Return type:

list[tuple[str, bool]]

mcparser.textinput.read_input(path)[source]

Read plain text (one sentence per line) or YAML (by file extension).

Parameters:

path (Path | str)

Return type:

list[InputSentence]

mcparser.textinput.build_sentences(entries)[source]

Unannotated sentences: ids, forms and SpaceAfter=No only.

Parameters:

entries (list[InputSentence])

Return type:

list[Sentence]

mcparser.textinput.blank_sentences(sentences)[source]

Copies with all annotation removed: ids, forms and SpaceAfter=No only.

Multiword tokens are kept (their split is part of the segmentation); empty nodes are dropped (they belong to the enhanced annotation). Other MISC attributes are dropped too, since they may hold glosses or other answers.

Parameters:

sentences (list[Sentence])

Return type:

list[Sentence]

Score predictions against gold CoNLL-U with the CoNLL 2018 shared task metrics.

The definitions and the word alignment are ported from the official conll18_ud_eval.py and tested against it (tests/official/), so the numbers agree with it exactly. Sentences are matched by sent_id instead of by position, so a partly annotated file can be scored. Surface tokens are aligned by their character span in the running text; words inside multiword tokens are then matched by form, so segmentation differences are counted rather than breaking the comparison. Each metric reports precision (over predicted words), recall (over gold words) and F1; with identical segmentation all three equal accuracy. run_official() runs the official script itself.

class mcparser.evaluate.MetricScore(*, metric, correct, gold, predicted, precision, recall, f1)[source]

Bases: BaseModel

Parameters:
  • metric (str)

  • correct (int)

  • gold (int)

  • predicted (int)

  • precision (float)

  • recall (float)

  • f1 (float)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class mcparser.evaluate.Evaluation(*, sentences, missing, extra, invalid=[], scores)[source]

Bases: BaseModel

Parameters:
  • sentences (int)

  • missing (list[str])

  • extra (list[str])

  • invalid (list[str])

  • scores (list[MetricScore])

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.evaluate.UNIVERSAL_FEATURES = frozenset({'Abbr', 'Animacy', 'Aspect', 'Case', 'Definite', 'Degree', 'Evident', 'Foreign', 'Gender', 'Mood', 'NumType', 'Number', 'Person', 'Polarity', 'Polite', 'Poss', 'PronType', 'Reflex', 'Tense', 'VerbForm', 'Voice'})

The relations and features the CoNLL 2018 scorer distinguishes (copied from conll18_ud_eval.py).

mcparser.evaluate.STRICT = ('UFeatsAll', 'AllTagsAll', 'LASFull')

all features (not only the universal ones) and the full relation (with its subtype).

Type:

Extra metrics with strict=True

mcparser.evaluate.official_problems(sentence)[source]

What the official scorer would reject in this sentence: a missing or impossible HEAD, a cycle, not exactly one root.

Parameters:

sentence (Sentence)

Return type:

list[str]

mcparser.evaluate.is_annotated(sentence)[source]

Whether every word has a HEAD, i.e. the sentence has been parsed.

Parameters:

sentence (Sentence)

Return type:

bool

mcparser.evaluate.evaluate(predicted, gold, predicted_only=False, annotated_only=False, strict=False)[source]

Score predicted against gold with the metrics of the CoNLL 2018 shared task (OFFICIAL).

The definitions follow conll18_ud_eval.py: UFeats and AllTags look at the universal features only, relation subtypes are ignored (obl:arg is obl), CLAS, MLAS and BLEX cover content words. With strict, three more metrics count language-specific features and relation subtypes (STRICT). Sentences are matched by sent_id rather than by position.

With predicted_only, gold sentences missing from the predictions are ignored (useful when only part of a test set was annotated). With annotated_only, only predicted sentences that have been parsed (every word has a HEAD) are scored, so unparsed sentences do not hide the accuracy of the parsed ones. Evaluation.invalid lists scored sentences the official scorer would refuse (no HEAD, a cycle, several roots); their wrong heads count as errors.

Parameters:
  • predicted (list[Sentence])

  • gold (list[Sentence])

  • predicted_only (bool)

  • annotated_only (bool)

  • strict (bool)

Return type:

Evaluation

mcparser.evaluate.scorable(sentence)[source]

A copy of sentence the official scorer accepts, or None if it needs no change.

For scoring only, never for output: a missing or impossible HEAD becomes the root, extra roots and cycles are attached to the first root (relation dep), and a sentence without a root gets one at its first word. Every repaired word is a wrong head and relation in all likelihood, so the scores are not flattered.

Parameters:

sentence (Sentence)

Return type:

Sentence | None

class mcparser.evaluate.OfficialResult(*, sentences, repaired, skipped=[], scores)[source]

Bases: BaseModel

The output of the official conll18_ud_eval.py for the sentences of a prediction file.

Parameters:
  • sentences (int)

  • repaired (list[str])

  • skipped (list[str])

  • scores (dict[str, MetricScore])

skipped: list[str]

left out of both files.

Type:

Gold sentences the official script cannot read (e.g. Arabic PADT afp.20000715.0008:p3u1)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.evaluate.run_official(script, predicted, gold)[source]

Run the official scorer (conll18_ud_eval.py, loaded from script) on the sentences in predicted.

The official scorer needs the same text in both files, so only gold sentences that were predicted are used, in gold order. Sentences it would refuse are repaired with scorable() first and listed in repaired.

Parameters:
Return type:

OfficialResult

mcparser.evaluate.CALIBRATION_EDGES = (0.5, 0.7, 0.8, 0.9, 0.95)

Lower edges of the confidence buckets (the first bucket starts at 0).

class mcparser.evaluate.CalibrationBucket(*, low, high, cells, correct)[source]

Bases: BaseModel

Parameters:
  • low (float)

  • high (float)

  • cells (int)

  • correct (int)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mcparser.evaluate.calibration(predicted, gold, columns=('upos', 'xpos', 'lemma', 'feats', 'head', 'deprel'))[source]

How accurate cells are, by the confidence recorded in MISC (Conf=).

Only cells of aligned words that carry a confidence count. A good scorer gives low scores to the cells that are wrong, so accuracy should rise with confidence; this shows where to set the refinement threshold.

Parameters:
Return type:

list[CalibrationBucket]