diff options
-rw-r--r-- | README.md | 11 | ||||
-rwxr-xr-x | cli.py | 34 | ||||
-rw-r--r-- | config.py | 4 | ||||
-rw-r--r-- | pyble.py | 112 |
4 files changed, 161 insertions, 0 deletions
@@ -22,6 +22,17 @@ You're going to need one or several translations. One possibility is to [get the $ ./cli.py load --type=biblehub bibles.txt $ rm bibles.zip bibles.txt +## Usage + +See `./cli.py --help` for general instructions and `./cli.py command --help` for command specific instructions. + +## Examples + + $ ./cli.py read 'John 1:1-3' --nl + 1:1 In the beginning was the Word, and the Word was with God, and the Word was God. + 2 The same was in the beginning with God. + 3 All things were made through him; and without him was not anything made that hath been made. + ## To do Add a table for cross references, and a script to read in the database from [OpenBible.info][openbibledb]. @@ -30,6 +30,39 @@ def init(): setup_fill_alternative_book_names(db) click.echo('Done.') +@cli.command() +@click.option('--nl/--no-nl', default=False, + help='Output every verse on a new line (default: false)') +@click.option('--vn/--no-vn', default=True, + help='Output verse and chapter numbers (default: true)') +@click.option('-t', '--translation', metavar='name', + help='Use a specific translation (default: config.py)') +@click.argument('reference', metavar='reference') +def read(nl, vn, translation, reference): + """Read a part of the Bible + + Examples: + + \b + cli.py read 'Genesis 1:1' + cli.py read 'Genesis 1:1' -t 'King James Bible' + cli.py read 'Gen 1:1-3' --no-vn + cli.py read 'Is 52:13-53:12' --nl + """ + passage = Passage.parse(reference) + chap = 0 + for v in passage.verses(): + if vn: + if chap != v.chapter: + chap = v.chapter + click.secho(str(chap) + ':', fg='yellow', nl=False) + click.secho(str(v.nr) + ' ', fg='cyan', nl=False) + + click.echo(str(v.get_translated(translation)) + ' ', nl=nl) + + if not nl: + click.echo() + def load_biblehub_line(columns, line): """Split a line from a Bible Hub dump into a usable dictionary @@ -105,5 +138,6 @@ def load(type, filename): click.secho('I don\'t know a type ' + type, fg='red') if __name__ == '__main__': + db = setup_database() cli() @@ -6,3 +6,7 @@ DATABASES = { } } +PYBLE_SETTINGS = { + 'default_translation': 'American Standard Version' + } + @@ -1,39 +1,151 @@ import csv + from orator import DatabaseManager, Model, Schema +from orator.exceptions.orm import ModelNotFound + +import re + +from config import * class Part(Model): __timestamps__ = False __fillable__ = ['name'] + __primary_key__ = 'name' class Book(Model): __timestamps__ = False __fillable__ = ['canonical_name'] + __primary_key__ = 'canonical_name' class AlternativeBookName(Model): __timestamps__ = False __fillable__ = ['book', 'name'] + __primary_key__ = 'name' class Verse(Model): __timestamps__ = False __fillable__ = ['book', 'chapter', 'nr'] + def __repr__(self): + return self.book + ' ' + str(self.chapter) + ':' + str(self.nr) + + def __str__(self): + return str(self.get_translated()) + + def get_translated(self, translation=None): + """Get the TranslatedVerse of this Verse and a Translation + + translation -- may be None, a string, or a Translation object + When None, the default (as in config.py) is used. + """ + if translation == None: + translation = PYBLE_SETTINGS['default_translation'] + tv = TranslatedVerse.where( + {'translation': str(translation), + 'book': self.book, + 'chapter': self.chapter, + 'nr': self.nr }).first() + return tv + class Translation(Model): __timestamps__ = False __fillable__ = ['name'] + __primary_key__ = 'name' + + def __str__(self): + return self.name class TranslatedVerse(Model): __timestamps__ = False __table__ = 'translated_verses' __fillable__ = ['translation', 'book', 'chapter', 'nr', 'text'] + def __repr__(self): + return book + ' ' + str(chapter) + ' ' + str(nr) + ' in ' + translation + + def __str__(self): + return self.text + class Passage(Model): __timestamps__ = False __fillable__ = ['fst', 'snd'] + def __repr__(self): + return repr(self.fst) + ' - ' + repr(self.snd) + + def __str__(self): + return ' '.join([str(v) for v in self.verses()]) + + def verses(self): + """An ordered list of the verses in this passage""" + vs = [] + book = self.fst.book + for c in range(self.fst.chapter, self.snd.chapter + 1): + vs_new = Verse.where({'book': book, 'chapter': c}) + if c == self.fst.chapter: + vs_new = vs_new.where('nr', '>=', self.fst.nr) + if c == self.snd.chapter: + vs_new = vs_new.where('nr', '<=', self.snd.nr) + vs = vs + list(vs_new.get()) + return vs + + @staticmethod + def parse(ref): + """Parse a Bible reference into a Passage object""" + rgx = re.compile(r"^([\s\w]+?[a-z]\b)(?:\s+" + "(\d+)(?::(\d+)(?:\-(\d+)(?::(\d+))?)?)?)?", re.I) + m = rgx.match(ref) + book, chap1, verse1, n1, n2 = m.groups() + chap1 = int(chap1) + + try: + book = AlternativeBookName.find_or_fail(book).book + except ModelNotFound: + return None + + p = Passage() + if verse1 == None: + try: + p.fst = Verse.where( + {'book': book, + 'chapter': chap1, + 'nr': 1}).first() + p.snd = Verse.where({'book': book, 'chapter': chap1})\ + .order_by('nr', 'desc').first() + except ModelNotFound: + return None + else: + chap1 = int(chap1) + try: + p.fst = Verse.where( + {'book': book, + 'chapter': chap1, + 'nr': verse1}).first() + if n1 == None: + p.snd = p.fst + elif n2 == None: + n1 = int(n1) + p.snd = Verse.where( + {'book': book, + 'chapter': chap1, + 'nr': n1}).first() + else: + n1 = int(n1) + n2 = int(n2) + p.snd = Verse.where( + {'book': book, + 'chapter': n1, + 'nr': n2}).first() + except ModelNotFound: + return None + + return p + class CrossReference(Model): __fillable__ = ['passage_id1', 'passage_id2', 'relevance'] def setup_fill_alternative_book_names(db): + """Fill the database with alternative book names from a CSV file""" with open('alternative_book_names.csv', 'r') as csvfile: reader = csv.reader(csvfile, delimiter=',', quotechar='"') db.begin_transaction() |