aegean.core¶
core ¶
Script-agnostic core: data model, script plugin contract, corpus, numerals.
Corpus ¶
Corpus(documents: list[Document], sign_inventory: SignInventory | None = None, provenance: Provenance | None = None, script_id: str = '')
A collection of Document s plus shared inventory + provenance.
load
classmethod
¶
Load a registered corpus by name, e.g. Corpus.load("lineara") (bundled)
or Corpus.load("damos") (fetched to the local data store on first use).
Loaders may cache one built instance per process (the bundled corpora do),
so the result is returned as a copy: mutate it freely, and documents
added, dropped, or edited never leak into later load calls.
version (optional) loads a kept historical release of a fetched corpus
that the project still hosts, for reproducing an earlier analysis byte-for-byte
(e.g. version="v1" for a pre-0.29.0 epigraphy corpus). It applies only to
the corpora with kept historical pins (isicily, iip, iospe,
igcyr, edh, ddbdp; see aegean.data.historical_versions) and
fetches into a separate version-suffixed cache entry, leaving the current data
untouched. The default (version=None) is unchanged.
get ¶
get(doc_id: str) -> Document | None
The document with id doc_id, or None if there is no such document.
fingerprint ¶
A stable content hash of this corpus, covering everything a token-level
analysis can see: the script id, the provenance data_version, each
document's id, every token's text, TokenKind, ReadingStatus, decomposed
signs, Unicode glyphs, alternate readings (alt), and annotations
(hashed as sorted key/value pairs), and any subset: / merged: /
appended: provenance note. Document metadata (site, period, ...) is
deliberately excluded. Cheap relative to the analyses it keys: one pass over
the tokens, no model build. Two corpora with the same fingerprint have the
same analysable content, so it's the cache key for aegean.cache-memoised
analyses (including the sign-level dispersion/keyness that read signs).
copy ¶
A structurally independent copy: a fresh document list and, per document,
fresh token/line/translation containers, so mutating the copy (or the
original) never affects the other. Token and Sign are frozen value
objects but each carries a mutable per-element dict (annotations /
attrs) for user analysis, so the copy rebuilds those with independent
dicts, keeping a per-token annotation edit (or a per-sign attr edit) from
leaking into the original, a sibling copy, or a later load of the same
cached corpus. The remaining fields (DocumentMeta, Provenance, the
immutable Token/Sign scalars) are shared. One pass over the tokens — a
fraction of a second even for the largest corpora (the annotation-rich NT
is the slowest); the copy fingerprints identically to the original.
filter ¶
Return a new Corpus whose documents match all given metadata fields
(AND-combination), e.g. corpus.filter(site="HT", period="LMIB").
The subset's provenance records what was filtered (a subset: note),
so cite on the result cites the exact subset used.
subset ¶
A new Corpus of just the documents whose id is in ids (original order kept).
The id-based counterpart to filter; records a subset: provenance note so cite
on the result names the slice.
merge ¶
Merge this corpus with others into one (documents concatenated in order).
dedupe controls duplicate document ids across the inputs: "error" (raise,
listing the collisions — the safe default), "first" / "last" (keep that
occurrence), or "suffix" (rename later collisions id#2, id#3, …). The
merged script_id is the common value, or "mixed" when the inputs differ; the
sign inventory is the first input's when scripts agree, else None. A fresh
provenance names every source, so cite on the result stays truthful.
See also aegean.combine, the module-level form that takes a list.
cite ¶
Cite this corpus — or the exact filtered subset — in one call.
style: "plain" (one line), "bibtex" (a @misc entry), or
"apa". Filtered subsets (see filter) carry a subset: note that
all three styles include, so the citation states exactly what was used.
iter_documents ¶
iter_documents() -> Iterator[Document]
Iterate documents (the explicit-name form of iter(corpus)).
iter_tokens ¶
iter_tokens() -> Iterator[Token]
Every Token, in document then in-document order — a memory-friendly
stream that never builds an all-tokens list (useful on a large corpus).
iter_words ¶
Every lexical (WORD) token's text, in order, lazily. The unit
word_frequencies counts — stream it to feed your own Counter or a
running statistic without materialising a list.
word_frequencies ¶
(word, count) for every lexical word, sorted by descending count.
diagnose ¶
A descriptive corpus-health report: reading-status profile, provenance /
citation completeness, Aegean accounting reconciliation, numeral anomalies,
annotation review state, and (level="full") sign-frequency outliers.
Composes existing public machinery into one aegean.core.diagnose.DiagnoseReport
(.print() / .to_markdown() / .to_dataframe()); every check degrades
gracefully on a corpus it does not apply to. Descriptive, not a verdict.
to_dataframe ¶
A pandas DataFrame at document, token, or word level.
pandas is an optional dependency — install with pip install 'pyaegean[data]'.
to_dict ¶
A compact, lossy export (_meta + per-document words/metadata) for quick
interop. For a complete, reversible serialization use to_json/from_json.
to_json ¶
Serialize the whole corpus to JSON losslessly — every token (with its kind,
signs, glyphs, line/position), the physical lines, full document metadata, the sign
inventory, and provenance all survive. from_json reverses it exactly.
Returns the JSON string, or writes it to path and returns None when path
is given. (Unlike to_dict, which is a compact lossy summary.)
from_json
classmethod
¶
Reconstruct a Corpus from to_json output: a JSON string, a Path to a
.json file, or a path-like string (anything not beginning with {).
from_records
classmethod
¶
from_records(records: Sequence[dict[str, Any]], *, script_id: str = 'custom', provenance: Provenance | None = None, sign_inventory: SignInventory | None = None) -> 'Corpus'
Build a corpus from plain dict records — your own inscriptions get the full API (filter, query, DataFrames, citation, export).
Each record needs an "id" and its text as one of:
"lines": a list of physical lines, each a list of tokens;"words": a flat token list (treated as one line);"text": a whitespace-tokenized string (one line).
A token is a string, or a dict {"text": …} with optional "kind"
(a TokenKind value; inferred when omitted — numerals by parseability,
the rest words), "status" (a ReadingStatus value), and "alt"
(alternate readings). Hyphenated tokens get their signs split.
Optional record keys: "meta" (site/period/scribe/support/findspot/
name), "translations". Example::
corpus = Corpus.from_records([
{"id": "X1", "text": "KU-RO 10", "meta": {"site": "My site"}},
{"id": "X2", "lines": [["A-DU", {"text": "5", "status": "unclear"}]]},
], script_id="lineara")
To make it loadable by name, register a loader:
aegean.core.corpus.register_loader("myfind", lambda: corpus).
from_dict
classmethod
¶
Reconstruct a Corpus from the dict to_json serializes (its json.loads).
Raises ValueError when the file records a schema version newer than this
release understands (a file from a future pyaegean), naming the fix; a missing
or older version loads normally.
to_sql ¶
Write this corpus to a SQLite database (stdlib only). Documents and tokens
become queryable rows with an optional FTS5 text index; provenance round-trips.
With append=True the documents are upserted into an existing database (by id)
instead of overwriting it. Reload with Corpus.from_sql; search with aegean.db.search.
from_sql
classmethod
¶
Reconstruct a Corpus from a SQLite database written by to_sql — the lossless
counterpart to from_json. For huge databases, aegean.db.stream yields documents
one at a time instead of loading them all.
query ¶
query(filters: Sequence[FilterRow], output: Output = 'inscriptions', *, annotated_ids: set[str] | None = None) -> QueryResults
Run the compound-query predicate engine over this corpus.
filters is a sequence of aegean.analysis.FilterRow rows (a field id, a
value, and optional connector/negate); output selects "inscriptions"
or "words". Returns aegean.analysis.QueryResults (.inscriptions and
.words) carrying this corpus's provenance and a summary of the filters,
so results.cite() cites the exact result set. In .words each count is
the word's document frequency (how many distinct inscriptions it occurs
in), not its token frequency; for token counts use word_frequencies. The
available fields are
in aegean.analysis.FIELDS. Unlike filter (exact metadata match), this
supports text/prefix/sign-pattern/co-occurrence predicates with AND/OR/NOT.
Document
dataclass
¶
Document(id: str, script_id: str, tokens: list[Token], lines: list[list[int]], glyphs: str = '', transcription: str = '', translations: list[str] = list(), meta: DocumentMeta = DocumentMeta())
DocumentMeta
dataclass
¶
DocumentMeta(site: str = '', support: str = '', scribe: str = '', findspot: str = '', period: str = '', name: str = '', images: tuple[str, ...] = (), notes: tuple[str, ...] = ())
Bibliographic / archaeological metadata for a document.
ReadingStatus ¶
Bases: str, Enum
Editorial certainty of a token's reading (Leiden / EpiDoc conventions).
CERTAIN is the default. The others mark the apparatus an epigraphic edition must
preserve — damaged, restored, or lost text. The bundled loaders decode each edition's
apparatus into these statuses (the Leiden underdots, brackets, and erasure marks of
the Cypriot and Linear A corpora); a bring-your-own EpiDoc corpus populates them from
<unclear> / <supplied> / <gap> markup, and the EpiDoc writer emits them
back.
Sign
dataclass
¶
Sign(label: str, glyph: str | None = None, codepoint: int | None = None, phonetic: str | None = None, script_id: str = '', attrs: dict[str, Any] = dict())
One graphic unit of a script (syllabogram, letter, or logogram).
SignInventory ¶
SignInventory(signs: list[Sign], script_id: str = '')
The set of signs for a script, indexed by label / glyph / codepoint.
copy ¶
An independent copy: each Sign is rebuilt with its own attrs dict.
Sign is a frozen value object but its attrs is a mutable per-sign dict for
user analysis; a shared/cached inventory (the @lru_cache-d *_inventory()
accessors) would otherwise let one caller's attrs edit leak into every later
reader and into a subsequent corpus load. Mirrors Corpus.copy for the sign layer.
Token
dataclass
¶
Token(text: str, kind: TokenKind, signs: tuple[str, ...] = (), glyphs: str | None = None, line_no: int | None = None, position: int | None = None, status: ReadingStatus = CERTAIN, alt: tuple[str, ...] = (), annotations: dict[str, str] = dict())
One unit in a document's transliterated text stream.
TokenKind ¶
Bases: str, Enum
The role a token plays in a document's text stream.
Provenance
dataclass
¶
Provenance(source: str, license: str = '', citation: str = '', url: str = '', schema_version: int = SCHEMA_VERSION, notes: tuple[str, ...] = tuple(), data_version: str = '', edition_fidelity: str = '')
Where a corpus came from and how to cite it.
bibtex ¶
A BibTeX @misc entry for this source.
Best-effort formatting of the recorded free-text provenance: only fields
actually known are emitted; the first year found in the citation string
(if any) becomes year; the license and any provenance notes (e.g.
the subset note Corpus.filter records) go into note.
apa ¶
An APA-style reference line (n.d. when no year is recoverable).
Best-effort formatting of the recorded free-text provenance; notes
(e.g. the subset note Corpus.filter records) follow in brackets.
Script ¶
Bases: ABC
A writing system the package can read and analyse.
register_loader ¶
Register a corpus loader so Corpus.load(script_id) / aegean.load(script_id) works.
get_script ¶
get_script(script_id: str) -> Script
Return the registered Script for script_id (raises KeyError if unknown).
register ¶
register(script: Script) -> None
Register a script plugin under its id (each built-in plugin calls this on import).
registered_scripts ¶
The sorted ids of all registered scripts, e.g. ['cypriot', 'cyprominoan', 'greek', 'lineara', 'linearb'].