Repos
repos
¶
Read-access repositories for the kotobase database
Each repository wraps a single session and turns queries into data transfer
objects. Headword lookups use the normalized form tables, meaning searches use
the gloss_fts full text index, and Japanese substring searches over sentences
use LIKE containment, which is reliable for kanji and kana text
Session Management
- Repositories never open their own session
- The
Unit Of Workowns one session and hands the same one to every repository it exposes
Error Handling
-
Every repository inherits from
KotobaseRepo, whose__init_subclass__wraps each public method so an unexpectedSQLAlchemyfailure surfaces as aDatabaseError -
Kotobase errors, such as a missing audio pack, pass through unchanged
AudioRepo
¶
Bases: KotobaseRepo
Repository for pronunciation audio metadata and clip bytes
The audio table lives in the optional audio pack, attached to the
connection only when installed. When it is absent the underlying query
raises an OperationalError, which both methods translate into an
AudioDatabaseNotFoundError
after rolling back the session
for_key(key, *, kind=None)
¶
Fetch audio clip metadata for a lookup key
Selects Audio rows whose key equals
key exactly, optionally narrowed to a single kind, and validates
each into an AudioDTO, which carries
provenance and format metadata but not the raw data bytes. When the
audio pack is not attached the query raises OperationalError, which
is caught, the session is rolled back, and an
AudioDatabaseNotFoundError is raised instead
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The lookup key, such as a kanji or word |
required |
kind
|
str | None
|
Restrict to a clip kind when given |
None
|
Returns:
| Type | Description |
|---|---|
list[AudioDTO]
|
The matching audio clips as metadata DTOs without the raw bytes, or
|
Raises:
| Type | Description |
|---|---|
AudioDatabaseNotFoundError
|
If the optional audio pack is not installed |
payloads(key, *, reading=None, kind=None)
¶
Fetch the file name and raw bytes of each matching audio clip
Selects Audio rows whose key equals
key exactly, optionally narrowed by exact reading and/or kind.
Rows whose data is None (metadata-only entries, such as remote
clips) are skipped. For the rest, a download file name is built as
<reading or key>.<fmt or "mp3"> and paired with the raw bytes. When
the audio pack is not attached the query raises OperationalError,
which is caught, the session is rolled back, and an
AudioDatabaseNotFoundError is raised instead
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The lookup key, such as a kanji or word |
required |
reading
|
str | None
|
Restrict to a single clip reading when given |
None
|
kind
|
str | None
|
Restrict to a clip kind when given |
None
|
Returns:
| Type | Description |
|---|---|
list[tuple[str, bytes]]
|
A |
Raises:
| Type | Description |
|---|---|
AudioDatabaseNotFoundError
|
If the optional audio pack is not installed |
FuriganaRepo
¶
Bases: KotobaseRepo
Repository for JmdictFurigana spelling-to-reading segmentation
for_text(text_value, reading=None)
¶
Fetch furigana segmentations for a written form
Selects Furigana rows whose text
equals text_value exactly. When reading is given it is added as a
second exact-match filter on Furigana.reading, narrowing to the one
spelling/reading pair (which is unique). Each row is validated into a
FuriganaDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text_value
|
str
|
The written spelling to look up |
required |
reading
|
str | None
|
A specific reading to narrow the match |
None
|
Returns:
| Type | Description |
|---|---|
list[FuriganaDTO]
|
The matching furigana segmentations as DTOs, or |
JLPTRepo
¶
Bases: KotobaseRepo
Repository for the Tanos JLPT vocabulary, kanji and grammar lists
Resolves a word or kanji to its JLPT level, searches grammar points by substring, and returns full per-level study lists. Each method validates rows into the matching JLPT DTO
grammar_like(query, *, limit=20)
¶
Find JLPT grammar points whose text contains the query
Selects up to limit JlptGrammar
rows whose grammar contains query as a substring
(LIKE '%query%'), ordered by descending level (so N1 grammar comes
before N5), and validates each into a
JLPTGrammarDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The substring to search for in grammar points |
required |
limit
|
int | None
|
Maximum number of grammar points to return |
20
|
Returns:
| Type | Description |
|---|---|
list[JLPTGrammarDTO]
|
The matching grammar points as DTOs ordered by descending level, or
|
kanji_by_literal(literal)
¶
Fetch the JLPT kanji entry for a literal
Selects the first JlptKanji row whose
kanji equals literal exactly (LIMIT 1) and validates it into a
JLPTKanjiDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
literal
|
str
|
The kanji character |
required |
Returns:
| Type | Description |
|---|---|
JLPTKanjiDTO | None
|
The JLPT kanji entry as a DTO, or |
kanji_levels(literals)
¶
Map each given kanji to its Tanos JLPT level
De-duplicates literals, then selects (kanji, level) from
JlptKanji where kanji is IN that
set. An empty input returns {} without a query
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
literals
|
Sequence[str]
|
The kanji to look up |
required |
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
A mapping of each listed kanji to its JLPT level, omitting kanji not in the Tanos list |
list_grammar(level)
¶
Return the full grammar study list for a level
Selects every JlptGrammar row whose
level equals level, ordered by ascending id (insertion order), then
validates each row into a
JLPTGrammarDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
int
|
The JLPT level from 1 to 5 |
required |
Returns:
| Type | Description |
|---|---|
list[JLPTGrammarDTO]
|
Every grammar point at the level as DTOs, or |
list_kanji(level)
¶
Return the full kanji study list for a level
Selects every JlptKanji row whose
level equals level, ordered by ascending id (insertion order), and
validates each into a JLPTKanjiDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
int
|
The JLPT level from 1 to 5 |
required |
Returns:
| Type | Description |
|---|---|
list[JLPTKanjiDTO]
|
Every kanji item at the level as DTOs, or |
list_vocab(level)
¶
Return the full vocabulary study list for a level
Selects every JlptVocab row whose
level equals level, ordered by ascending id (insertion order), and
validates each into a JLPTVocabDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
int
|
The JLPT level from 1 to 5 |
required |
Returns:
| Type | Description |
|---|---|
list[JLPTVocabDTO]
|
Every vocabulary item at the level as DTOs, or |
vocab_by_word(word)
¶
Find the JLPT vocabulary entry for a word or reading
Selects the first JlptVocab row whose
word or reading equals word exactly (LIMIT 1), and validates it
into a JLPTVocabDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
word
|
str
|
The headword or reading to look up |
required |
Returns:
| Type | Description |
|---|---|
JLPTVocabDTO | None
|
The vocabulary entry as a DTO, or |
JMDictRepo
¶
Bases: KotobaseRepo
Repository that abstracts queries over the JMdict tables
Looks up entries by sequence number, by written or reading form against the
normalized jmdict_kanji / jmdict_kana tables, and by English meaning
through the gloss_fts full-text index. Every method eagerly loads kanji
forms, kana forms and senses with their glosses (_JMDICT_LOAD) and
returns JMDictEntryDTO objects built
with model_validate
by_id(entry_id)
¶
Fetch one entry by its JMdict sequence number
Loads the row through Session.get with _JMDICT_LOAD eager loading
of its kanji forms, kana forms and senses with glosses, then validates
it into a JMDictEntryDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entry_id
|
int
|
The |
required |
Returns:
| Type | Description |
|---|---|
JMDictEntryDTO | None
|
The entry as a DTO, or |
resolve_reference(ref)
¶
Resolve a cross-reference or antonym code to its entries
JMdict xref and antonym codes are ・-separated into a leading
form and an optional disambiguating reading and sense number. This
takes the part before the first ・, strips it, and when it is
non-empty looks it up exactly through search_form with no limit (the
reading and sense number are ignored). An empty leading form returns
[] without querying
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ref
|
str
|
The cross-reference or antonym code to resolve |
required |
Returns:
| Type | Description |
|---|---|
list[JMDictEntryDTO]
|
The entries the leading form points to, or |
search_form(form, *, wildcard=False, limit=50)
¶
Search entries by a written or reading form
Matches form against JMDictKanji.text or JMDictKana.text through
a non-correlated id IN (SELECT entry_id ... UNION SELECT entry_id
...) subquery, which SQLite drives off the ix_jmdict_kanji_text /
ix_jmdict_kana_text indexes instead of scanning every entry. By
default the comparison is exact. When wildcard is True, * is
translated to % and the form is matched as a SQL LIKE pattern.
Results are eager-loaded with _JMDICT_LOAD, ordered by
_JMDICT_ORDER, and capped at limit
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
form
|
str
|
The query form, where |
required |
wildcard
|
bool
|
When True, treat the query as a |
False
|
limit
|
int | None
|
Maximum entries to return, or |
50
|
Returns:
| Type | Description |
|---|---|
list[JMDictEntryDTO]
|
The matching entries as DTOs, or |
search_gloss(query, *, limit=50)
¶
Search entries by English meaning through the gloss_fts index
Runs a raw FTS5 query that matches query against the gloss_fts
virtual table (gloss_fts MATCH :query), joined to jmdict_sense to
recover each matching sense's entry_id, capped at limit rows. The
entry ids are de-duplicated while preserving first-seen order, then
re-fetched and ordered through _by_ids, so the final ordering is the
canonical commonness/frequency order rather than relevance
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The |
required |
limit
|
int | None
|
Maximum number of |
50
|
Returns:
| Type | Description |
|---|---|
list[JMDictEntryDTO]
|
The matching entries as DTOs, or |
JMNeDictRepo
¶
Bases: KotobaseRepo
Repository that abstracts queries over the JMnedict proper-name tables
Looks up names by sequence number, by written or reading form against the
normalized jmnedict_kanji / jmnedict_kana tables, and by name type.
Every method eagerly loads kanji forms, kana forms and translation blocks
with their glosses (_JMNEDICT_LOAD) and returns
JMNeDictEntryDTO objects built with
model_validate
browse_by_type(name_type, *, limit=50)
¶
Browse names that carry a given name type
The name_type codes of a block are stored as a JSON list in
JMnedictTranslation.name_type, so this matches the quoted code as a
substring (LIKE '%"<name_type>"%') to find translation blocks of that
type, collecting up to limit distinct owning entry_id values. Those
entries are then re-fetched eager-loaded with _JMNEDICT_LOAD and
ordered by ascending id. When no block matches, returns [] without
the second query
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name_type
|
str
|
The name type code such as |
required |
limit
|
int | None
|
Maximum number of distinct entry ids to collect |
50
|
Returns:
| Type | Description |
|---|---|
list[JMNeDictEntryDTO]
|
The matching names as DTOs ordered by id, or |
by_id(entry_id)
¶
Fetch one name entry by its JMnedict sequence number
Loads the row through Session.get with _JMNEDICT_LOAD eager loading
of its kanji forms, kana forms and translation blocks with glosses,
then validates it into a
JMNeDictEntryDTO
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entry_id
|
int
|
The |
required |
Returns:
| Type | Description |
|---|---|
JMNeDictEntryDTO | None
|
The name entry as a DTO, or |
search(form, *, wildcard=False, limit=50)
¶
Search names by a written or reading form
Matches form against JMnedictKanji.text or JMnedictKana.text
through a non-correlated id IN (SELECT entry_id ... UNION SELECT
entry_id ...) subquery, which SQLite drives off the
ix_jmnedict_kanji_text / ix_jmnedict_kana_text indexes instead of
scanning every entry. By default the comparison is exact. When
wildcard is True, * is translated to % and the form is matched
as a SQL LIKE pattern. Results are eager-loaded with
_JMNEDICT_LOAD, ordered by ascending JMnedictEntry.id and capped
at limit
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
form
|
str
|
The query form, where |
required |
wildcard
|
bool
|
When True, treat the query as a |
False
|
limit
|
int | None
|
Maximum entries to return, or |
50
|
Returns:
| Type | Description |
|---|---|
list[JMNeDictEntryDTO]
|
The matching names as DTOs ordered by id, or |
KanjiRepo
¶
Bases: KotobaseRepo
Repository that abstracts KanjiDic2 lookups enriched with extras
Reads kanji from the kanji table, eager-loading every per-character
relationship, and joins in two pieces that
are not kanji relationships, the KRADFILE radical components and the
Tanos JLPT level, which are injected through _kanji_payload when
validating each KanjiDTO. Also serves
stroke-order SVG and lookups by SKIP code or scalar attribute
bulk_fetch(literals)
¶
Fetch several kanji at once, preserving first-seen input order
De-duplicates literals while keeping order, then selects the matching
Kanji rows (literal IN ...)
eager-loaded with _KANJI_LOAD, and gathers their radical components
and Tanos JLPT levels through _radicals and _jlpt_levels. Each
found kanji is built into a KanjiDTO via
_kanji_payload, which injects that kanji's radicals and JLPT level,
and the results are emitted in input order. Requested literals with no
kanji row are skipped, so the result may be shorter than the input.
An empty input returns [] without a query
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
literals
|
Sequence[str]
|
The kanji characters to fetch |
required |
Returns:
| Type | Description |
|---|---|
list[KanjiDTO]
|
The matching kanji as DTOs in input order, or |
by_literal(literal)
¶
Fetch one kanji with its full profile
Thin wrapper that delegates to bulk_fetch with a single literal and
unwraps the result
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
literal
|
str
|
The kanji character |
required |
Returns:
| Type | Description |
|---|---|
KanjiDTO | None
|
The kanji as a |
by_skip(code, *, limit=100)
¶
Find kanji with a given SKIP query code
Selects up to limit literal values from
KanjiQueryCode where type is
skip and value equals code exactly, then re-fetches their full
profiles through bulk_fetch
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
str
|
The SKIP code such as |
required |
limit
|
int | None
|
Maximum number of matching literals to collect |
100
|
Returns:
| Type | Description |
|---|---|
list[KanjiDTO]
|
The matching kanji as DTOs, or |
search(*, stroke_count=None, grade=None, freq_max=None, jlpt=None, limit=100)
¶
Search kanji by scalar attributes
Builds a select over Kanji.literal, adding a filter for each
non-None argument. The literals are ordered with kanji
that have a freq ahead of those without, then by ascending freq,
then by character, capped at limit, and re-fetched as full profiles
through bulk_fetch
Filters
stroke_countandgradematch exactlyfreq_maxkeeps only kanji whosefreqis set and<= freq_max-
jlptrestricts to literals present inJlptKanjiat that level (subquery) -
Omitted arguments add no filter
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stroke_count
|
int | None
|
Required exact stroke count |
None
|
grade
|
int | None
|
Required exact school grade |
None
|
freq_max
|
int | None
|
Maximum newspaper frequency rank |
None
|
jlpt
|
int | None
|
Required Tanos JLPT level |
None
|
limit
|
int | None
|
Maximum number of matching literals to collect |
100
|
Returns:
| Type | Description |
|---|---|
list[KanjiDTO]
|
The matching kanji as DTOs, ordered by frequency then character, or
|
stroke_svg(literal, *, raw=False)
¶
Fetch a kanji's KanjiVG stroke order as SVG
Loads the KanjiStrokes row by its
literal primary key. By default the stored KanjiVG <kanji> markup
is wrapped through _svg_document into a self-contained, browser
renderable <svg> document. Pass raw to get that stored <kanji>
fragment verbatim instead, which has no <svg> root or styling
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
literal
|
str
|
The kanji character |
required |
raw
|
bool
|
When True, return the raw KanjiVG fragment unwrapped |
False
|
Returns:
| Type | Description |
|---|---|
str | None
|
The stroke order SVG, or |
KotobaseRepo
¶
Base class for a repository that runs queries through one shared session
Error Handling
-
Subclassing also installs the central error wrapping
-
Every public method a subclass defines is replaced with a version that converts a raised
SQLAlchemyErrorinto aDatabaseError, so individual methods only document their own non-SQLAlchemyraises
Attributes:
| Name | Type | Description |
|---|---|---|
session |
Session
|
The session, owned by the unit of work, that every query on this repository runs through |
__init__(session)
¶
Store the session this repository runs all of its queries through
The session is not opened or owned here, it is supplied by the unit of work and shared with the other repositories
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
Session
|
The active session to query through |
required |
__init_subclass__(**kwargs)
¶
Wrap each public method the subclass defines with the SQLAlchemy
error handler
Iterates the subclass's own vars, and for every callable, non-_
attribute, replaces it with the result of _wrap_sqlalchemy_error, so
a raised SQLAlchemyError surfaces as a
DatabaseError while a
KotobaseError passes through
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Any
|
Extra arguments forwarded to the base hook |
{}
|
RadicalRepo
¶
Bases: KotobaseRepo
Repository for the RADKFILE / KRADFILE radical decomposition data
Lists the RADKFILE search radicals, reads a kanji's radical components,
and performs reverse radical search, finding the kanji that contain a
chosen set of radicals
kanji_by_radicals(radicals, *, match='all')
¶
Find kanji that contain the given radicals (reverse radical search)
De-duplicates radicals, then groups
KanjiRadical rows whose radical
is IN that set by literal. With match="all" a HAVING clause
keeps only kanji whose distinct matched-radical count equals the number
of requested radicals, so every radical is required (intersection). Any
other match value (such as "any") drops the HAVING clause, so a
kanji that contains at least one of the radicals matches (union). An
empty radicals argument returns [] without a query
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
radicals
|
Sequence[str]
|
The radical components to match against |
required |
match
|
str
|
|
'all'
|
Returns:
| Type | Description |
|---|---|
list[str]
|
The matching kanji literals, or |
list_radicals()
¶
List every RADKFILE search radical with its stroke count
Selects all Radical rows ordered by
ascending stroke_count then radical character, and validates each
into a RadicalDTO
Returns:
| Type | Description |
|---|---|
list[RadicalDTO]
|
Every search radical as a DTO, ordered by stroke count then character |
radicals_of(literal)
¶
List the KRADFILE radical components of one kanji
Selects the radical column from
KanjiRadical for rows whose
literal equals the kanji exactly, in primary-key order
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
literal
|
str
|
The kanji character |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
The radical components contained in the kanji, or |
SentenceRepo
¶
Bases: KotobaseRepo
Repository for Tatoeba example sentences and their translations
search_containing(query, *, limit=20, wildcard=False)
¶
Find Japanese sentences containing the query text, with translations
Selects up to limit Sentence rows
where lang is jpn and text matches a SQL LIKE pattern, ordered
by ascending id. By default the query is wrapped as %query% substring
containment. When wildcard is True, * is translated to % and the
query is used as the LIKE pattern directly. For the matched sentences
it then resolves translations by joining
SentenceLink (whose source_id is
the Japanese sentence) to the target Sentence.text, grouping the
translation texts per source id. Each sentence is validated into a
SentenceDTO with its translations
injected through the validation context
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The text to search for, where |
required |
limit
|
int | None
|
Maximum number of sentences to return |
20
|
wildcard
|
bool
|
When True, treat the query as a |
False
|
Returns:
| Type | Description |
|---|---|
list[SentenceDTO]
|
The matching sentences as DTOs with their aligned translations, or
|
TagRepo
¶
Bases: KotobaseRepo
Repository for the tag dictionary that expands codes to descriptions
labels(codes)
¶
Map tag codes to their human readable descriptions
De-duplicates codes, then selects (code, description) from
Tag where code is IN that set. Because
the lookup is by code alone (not by category), a code shared across
tag families collapses to a single description. An empty input returns
{} without a query
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
codes
|
Sequence[str]
|
The tag codes to expand |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
A mapping of code to description for the codes that are known, omitting any that are not in the tag table |