name_key
def name_key(
s:str
)->str:Return one key for every spelling of a Sanskrit name in IAST, plain roman, Indian English or Devanagari: Bhīṣma, Bheeshma and भीष्म all give bisma.
Readers search for names and terms in whatever spelling they know, and translations write them in yet another. This module closes the gap in three ways: one key for every spelling of a name, a table of epithets, and a table of English glosses for technical terms.
A reader may write Krishna, Kṛṣṇa, krsna or कृष्ण; Bheeshma or Bhīṣma; Venkateshwara or Veṅkaṭeśvara. name_key gives every spelling of a name one key. It applies fold_token and then the habits of Indian-English spelling: ṛ is read as ri, sh as s, w as v, ee and oo as i and u, the h of an aspirate is dropped, and doubled letters become single. Bhīṣma, Bheeshma and भीष्म all give bisma. The key is for matching only, not a spelling to show anyone.
name_key differs from roman_fold in ganapati.sanskrit mainly in its treatment of ṛ. roman_fold reads Krishna as krsna, matching a transliteration, while name_key reads Kṛṣṇa as krisna, matching the way the name is usually spelled in English.
Return one key for every spelling of a Sanskrit name in IAST, plain roman, Indian English or Devanagari: Bhīṣma, Bheeshma and भीष्म all give bisma.
assert name_key('Bhīṣma') == name_key('Bheeshma') == name_key('bhishma') == name_key('भीष्म') == 'bisma'
assert name_key('Kṛṣṇa') == name_key('Krishna') == name_key('कृष्ण') == 'krisna'
assert name_key('Veṅkaṭeśvara') == name_key('Venkateshwara') == name_key('Venkateswara')
assert name_key('Yudhiṣṭhira') == name_key('Yudhishthira') == 'yudistira'
assert name_key('Lakṣmaṇa') == name_key('Lakshmana') and name_key('Kārttikeya') == name_key('Kartikeya')
assert name_key('Bhīma') != name_key('Bhīṣma')
assert name_key('') == ''Some spellings still differ after name_key. Plain roman drops the vowel that IAST writes as ṛ (krsna for kṛṣṇa), Indian English adds one (krishna), and Indian English often drops a final a (arjun). name_variants looks in a pool of keys, such as the vocabulary of an index, and returns the ones that differ from a given key by a single vowel added or removed, with the same first letter. It never adds or removes a consonant, because Bhīma (bima) and Bhīṣma (bisma) are different people. A key shorter than min_len, five letters by default, matches only itself, since one vowel more on a short name often makes another name.
Return the keys in pool that spell the same name as key: the key itself and, from min_len letters on, keys one vowel longer or shorter with the same first letter.
pool = {'krsna', 'krisna', 'bima', 'bisma', 'arjuna', 'rama'}
assert name_variants('krsna', pool) == {'krsna', 'krisna'}
assert name_variants('krisna', pool) == {'krsna', 'krisna'}
assert name_variants('bisma', pool) == {'bisma'} # not bima: a dropped consonant is another name
assert name_variants('arjun', pool) == {'arjuna'} # Indian-English drops the final a
assert name_variants('ram', pool) == set() # under min_len: rama is not tried
assert name_variants('karisana', {'krsna'}) == set() # three vowelsAn epithet is a descriptive name for a deity or a hero: Pārtha, son of Pṛthā, for Arjuna, or Raṅganātha, lord of Raṅga, for Viṣṇu. A reader may search for the epithet when the translation writes only the main name. EPITHETS holds one group per line: first the canonical names that translations use, then |, then the epithets.
The mapping goes one way. Raṅganātha leads to Viṣṇu, Nārāyaṇa and Hari, but Viṣṇu does not lead to every epithet, so a search for Rāma is not widened to every Rāghava. An epithet that two figures share is in both groups, as Acyuta and Mādhava are. A name that more often means something else is left out: Śrī; Ramā (Lakṣmī), whose key rama is Rāma’s; Kṛṣṇā (Draupadī), whose key is Kṛṣṇa’s; Guha, which is Skanda but also the boatman of the Rāmāyaṇa; and Kaunteya, which is any son of Kuntī. Spellings that name_key cannot bring together are listed beside the IAST, such as Subramanya, Murugan and Bajrangbali. The names are common knowledge from the epics, the Purāṇas and temple usage, written in IAST.
canonical is the function to call. It takes a name in any spelling and returns the canonical names it leads to: an epithet’s group, a canonical name’s own group, or () if the table does not have it. It also accepts a leading Śrī, Śrīmat or Bhagavān, ṛ typed as a plain r, an English plural, and, for names of five letters or more, a dropped final a, as in Ganesh for Gaṇeśa. epithets returns the whole map from epithet keys to canonical names.
Return the canonical names that name, in any spelling, leads to, or () if the table does not have it.
Return the map from each epithet’s name_key to the canonical names a translation writes, such as ranganata to Viṣṇu, Nārāyaṇa and Hari.
assert canonical('Raṅganātha') == ('viṣṇu', 'nārāyaṇa', 'hari') == canonical('Sri Ranganatha') == canonical('Srinivasa')
assert canonical('Venkateshwara') == canonical('Balaji') == canonical('perumal') == ('viṣṇu', 'nārāyaṇa', 'hari')
assert canonical('Nārāyaṇa') == ('viṣṇu', 'nārāyaṇa', 'hari') # a canonical name gives its group
assert canonical('Dāśarathi') == canonical('Raghava') == canonical('dasarathi') == ('rāma',)
assert canonical('Partha') == canonical('Dhananjaya') == canonical('धनञ्जय') == ('arjuna',)
assert canonical('Jānakī') == canonical('Vaidehi') == ('sītā',) and canonical('Maruti') == canonical('Anjaneya') == ('hanumān', 'hanumat')
assert canonical('Murugan') == canonical('Subramanya') == ('skanda', 'kārttikeya', 'subrahmaṇya')
assert canonical('Vinayaka') == canonical('Ganesh') == ('gaṇeśa', 'gaṇapati') # Ganesh: the final a dropped
assert canonical('Shankar') == canonical('Mahadeva') == ('śiva',) and canonical('Ambika') == ('pārvatī', 'umā', 'gaurī')
assert set(canonical('Acyuta')) == {'viṣṇu', 'nārāyaṇa', 'hari', 'kṛṣṇa'} # an epithet two groups share
assert canonical('Keśava') == canonical('Kesava') == ('kṛṣṇa',) and canonical('Krishna') == canonical('krsna') == ('kṛṣṇa',) # krsna: ṛ typed as r
assert canonical('Gangeya') == ('bhīṣma',) and canonical('Vrkodara') == ('bhīma',)
assert canonical('hrsikesa') == canonical('Hrishikesha') == canonical('krsna') == ('kṛṣṇa',)
assert canonical('dharma') == canonical('karma') == canonical('') == ()
assert canonical('part') == canonical('anal') == canonical('rudhira') == canonical('ram') == () # English words and short stems stay outThe table is checked for one mistake: an epithet whose key is also the canonical name of a different group, which would widen every search for that name.
TERMS gives the English that translations use for the technical terms of the śāstras: the means of knowledge (pramāṇas) and the categories of Nyāya, the padārthas of Vaiśeṣika, Sāṃkhya and Yoga, Vedānta and the Gītā, and the calendar (pañcāṅga) and the horoscope. Each term has a few English glosses, the most usual first. term_gloss looks a term up by name_key, so anumāna, anumana and अनुमान are one term, and an English plural such as gunas works too. Śraddhā (faith) is left out because its key is the same as that of śrāddha, the rite for the ancestors.
A term not in the table falls back to Monier-Williams (mw_lexicon in ganapati.lemma) when you pass it as mw or it has already been downloaded; term_gloss never downloads anything. The fallback looks the term up by its SLP1 form, so it works for IAST and Devanagari but not for informal spellings, and it returns at most three glosses. terms returns the whole table by key.
Return short English glosses for a Sanskrit technical term from TERMS, else from Monier-Williams, or () if neither knows it.
Return every term in TERMS by name_key, mapped to its English glosses.
assert term_gloss('anumāna') == term_gloss('anumana') == term_gloss('अनुमान') == ('inference',)
assert term_gloss('pratyaksha') == ('perception',) and term_gloss('upamana') == ('comparison', 'analogy')
assert term_gloss('saṃśaya') == term_gloss('samshaya') == ('doubt',) and term_gloss('dravya') == ('substance',)
assert term_gloss('sthitaprajña') == ('steady wisdom',) and term_gloss('moksha') == ('liberation', 'release')
assert term_gloss('nakshatra') == ('lunar mansion', 'asterism') and term_gloss('lagna') == ('ascendant',)
assert term_gloss('padarthas') == ('category',) and term_gloss('gunas') == ('quality',) and term_gloss('tamas') == ('darkness', 'inertia')
assert term_gloss('anumāna', mw={}) == ('inference',) and term_gloss('shraddha', mw={}) == () # the table needs no MW; śrāddha is no term
assert term_gloss('gaja', mw={'gaja': 'an elephant; the number 8'}) == ('an elephant', 'the number 8')
assert term_gloss('xyz', mw={}) == () and term_gloss('', mw={}) == ()
assert len(_TERMS) == len(TERMS.strip().splitlines()) > 120 # no two terms share a keyThe two tables do not overlap: no technical term has the same key as a name.