#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Wrapper implementation of Dbt API.
Usage:
>>> from versify import Dbt
>>> dbt = Dbt(config_path="/path/to/config.ini")
>>> print(dbt.find_verse("DBY", "1 Timothée", 2, 1))
"""
import random
import configparser
import requests
from requests import RequestException, ConnectTimeout, Timeout
from requests.exceptions import ProxyError, HTTPError
from versify.model.Book import Book
from versify.model.Chapter import Chapter
from versify.model.Testament import Testament
from versify.model.Verse import Verse
from versify.model.Version import Version
[docs]def get_config(config_path):
"""
Get config data
:param config_path: filepath of config ini file
:return: instance of ini config file
"""
config = configparser.ConfigParser()
config.read(config_path)
return config
[docs]def levenshtein_distance(a, b):
"""Return the Levenshtein edit distance between two strings *a* and *b*."""
if a == b:
return 0
if len(a) < len(b):
a, b = b, a
if not a:
return len(b)
previous_row = range(len(b) + 1)
for i, column1 in enumerate(a):
current_row = [i + 1]
for j, column2 in enumerate(b):
insertions = previous_row[j + 1] + 1
deletions = current_row[j] + 1
substitutions = previous_row[j] + (column1 != column2)
current_row.append(min(insertions, deletions, substitutions))
previous_row = current_row
return previous_row[-1]
[docs]class Dbt:
"""
This class implement a wrapper on API Dbt
"""
def __init__(self, config_path):
self.config = get_config(config_path)
self.base_url = "https://dbt.io"
self.dbt_version = "2"
self.retry_delay = 5000
self.max_attemps = 3
self.language = self.config.get("dbt", "lang")
self.dbt_key = self.config.get("dbt", "key")
self.osis_codes = self.get_osis_code()
@staticmethod
def book_equals(book_name1, book_name2):
book_name1 = book_name1.replace("IIIième ", "3").replace("IIième ", "2").replace("Iier ", "1")
book_name2 = book_name2.replace("IIIième ", "3").replace("IIième ", "2").replace("Iier ", "1")
return book_name1.lower().strip() == book_name2.lower().strip()
[docs] def get_request(self, url, attempt=0):
"""
This function make get request on url with some attemps
:param url: url to make your get request
:param attempt: number of the current attempt
:return: response object of get request
"""
try:
return requests.get(url=url).json()
except (RequestException, HTTPError, ProxyError, Timeout, ConnectTimeout):
if attempt < self.max_attemps:
return self.get_request(url, attempt + 1)
return None
def get_api_url(self, path, params):
url = "{}{}?v={}&key={}".format(self.base_url, path, self.dbt_version, self.dbt_key)
for key, value in params.items():
url += "{}&{}={}".format(url, key, value)
return url
[docs] def get_osis_code(self):
"""
Get the list of osis codes on Dbt
:return: list of osis code on Dbt
"""
result = {}
url = self.get_api_url("/library/bookname", {"language_code": self.language})
data = self.get_request(url)
for item in data:
for k, v in item.items():
result[k] = v.replace("IIIième ", "3").replace("IIième ", "2").replace("Iier ", "1")
return result.values()
[docs] def find_chapter(self, version, book, chapter_number):
"""
Find a chapter object in book
:param version: bible version instance
:param book: book instance
:param chapter_number: number of chapter
:return: Instance of chapter
"""
book = self.normalize_book(book)
bk = self.find_book(version, book)
return Chapter(bk, chapter_number)
[docs] def find_book(self, vers, book_name):
"""
Find a book in bible
:param vers: bible version instance
:param book_name: name of book in string
:return: Instance of book
"""
version = self.find_version(vers)
for t in version.testaments:
url = self.get_api_url("/library/book", {"dam_id": t.damn_id})
books = self.get_request(url)
for book in books:
if Dbt.book_equals(book['book_name'], book_name):
b = Book(t,
book['book_name'],
book['book_id'],
book['book_order'])
list_chapters = book['chapters'].split(',')
for c in list_chapters:
b.chapters.append(Chapter(b, c))
return b
return None
def find_version(self, version_param):
url = self.get_api_url("/library/volume", {"language_family_code": self.language, "media": "text"})
testaments = self.get_request(url)
version = None
for testament in testaments:
if version_param != testament["version_code"]:
continue
if version is None:
version = Version(testament['version_name'], testament['version_code'])
t = Testament(testament['volume_name'],
testament['dam_id'],
testament['collection_code'],
version)
version.testaments.append(t)
return version
def get_neighbord(self, book_name):
board = {}
for osis_code in self.osis_codes:
board[osis_code] = levenshtein_distance(osis_code, book_name)
code = min(board, key=board.get)
#
if board[code] <= 3:
return code
else:
return None
def normalize_book(self, book):
book = book.strip()
find_code = False
for osis_code in self.osis_codes:
if Dbt.book_equals(osis_code, book):
find_code = True
if not find_code:
old_book = book
book = self.get_neighbord(book)
if book is None:
print("Book '{}' doesn't exist in OSIS Code list."
" Please get on this list : {}".format(old_book, self.osis_codes))
return None
return book
def find_verse(self, version, book, chapter_number, verse_number):
book = self.normalize_book(book)
if book is not None:
ch = self.find_chapter(version, book, chapter_number)
url = self.get_api_url("/text/verse", {
"dam_id": ch.book.testament.damn_id,
"book_id": ch.book.code,
"chapter_id": ch.chapter_number,
"verse_start": verse_number
})
verses = self.get_request(url)
for verse in verses:
return Verse(ch,
verse['verse_id'],
verse['verse_text'].strip())
return None
[docs] def get_random_verse(self, version):
"""
Get a random verse on bible
:param version: text version of bible (DBY, etc.)
:return: instance of Verse object
"""
version_obj = Version(version, version)
testaments = version_obj.get_testaments(self)
select_testament = random.choice(testaments)
books = select_testament.get_books(self)
select_book = random.choice(books)
chapters = select_book.get_chapters()
select_chapter = random.choice(chapters)
verses = select_chapter.get_verses(self)
select_verse = random.choice(verses)
return select_verse