diff --git a/README.md b/README.md index cffa2e7..27fdcc9 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ The `getBible Librarian` package is a Python library designed for efficiently re ## Features +- [Get Scripture](https://git.vdm.dev/getBible/librarian/src/branch/master/docs/getbible_scripture.md) - [Get Reference](https://git.vdm.dev/getBible/librarian/src/branch/master/docs/getbible_reference.md) - [Get Book Number](https://git.vdm.dev/getBible/librarian/src/branch/master/docs/getbible_book_number.md) diff --git a/docs/getbible_book_number.md b/docs/getbible_book_number.md index 69e4d33..fb5f211 100644 --- a/docs/getbible_book_number.md +++ b/docs/getbible_book_number.md @@ -10,7 +10,11 @@ The `GetBibleBookNumber` package is a Python library designed for efficiently re - Provides functionality to dump Trie data into a JSON file for review. - Fallback search mechanisms for comprehensive reference coverage. -## Installation +## Installation (pip) + +To install the package using pip, see [the documentation](https://git.vdm.dev/getBible/-/packages/pypi/getbible-librarian). + +## Installation (git) To install `GetBibleBookNumber`, you need to clone the repository and install the package manually. Ensure you have Python 3.7 or higher installed. @@ -84,4 +88,3 @@ Contributions to the `GetBibleBookNumber` class is welcome. Please ensure to fol ## License This project is licensed under the GNU GPL v2.0. See the LICENSE file for more details. - diff --git a/docs/getbible_deploy_gitea.md b/docs/getbible_deploy_gitea.md new file mode 100644 index 0000000..11eb083 --- /dev/null +++ b/docs/getbible_deploy_gitea.md @@ -0,0 +1,79 @@ +# Guide to Building and Deploying a GetBible Package to Our Gitea's PyPI Package Registry + +This guide focuses on building your Python package and deploying it to your Gitea system's PyPI package registry. The provided documentation gives a clear outline of the requirements and steps needed. + +## Prerequisites + +- Python and necessary build tools installed. +- `pip` for package installation. +- `twine` for package uploading. + +## Step 1: Building the Python Package + +### 1.1 Create a Source Distribution + +Navigate to your package directory and run: + +```bash +python setup.py sdist +``` + +This creates a source distribution in the `dist/` folder. + +### 1.2 Create a Wheel Distribution + +For a wheel (`.whl`) distribution: + +```bash +python setup.py bdist_wheel +``` + +This places a wheel file in the `dist/` folder. + +## Step 2: Configuring the Package Registry + +### 2.1 Edit `~/.pypirc` + +Add the following to your `~/.pypirc` file: + +```ini +[distutils] +index-servers = getbible + +[getbible] +repository = https://git.vdm.dev/api/packages/getbible/pypi +username = {username} +password = {token} +``` + +Replace `{owner}`, `{username}`, and `{token}` with your Gitea details. + +For more information on the PyPI registry, [see the documentation](https://docs.gitea.com/usage/packages/pypi/). + +## Step 3: Publish the Package + +### 3.1 Upload Package + +Run the following command to upload your package: + +```bash +python3 -m twine upload --repository getbible dist/* +``` + +This uploads all files in the `dist/` directory (`.tar.gz` and `.whl`). + +**Note:** You cannot publish a package if a package of the same name and version already exists. + +## Step 4: Install the Package + +### 4.1 Install Using pip + +To install a package from the Gitea package registry: + +```bash +pip install --index-url https://git.vdm.dev/api/packages/getBible/pypi/simple/ getBible-librarian +``` + +## Conclusion + +You now have a straightforward process for building and deploying a Python package to your Gitea system's PyPI package registry. This setup ensures a seamless workflow for managing and distributing Python packages within your organization or for personal use. diff --git a/docs/getbible_reference.md b/docs/getbible_reference.md index 10f2f76..a481fa0 100644 --- a/docs/getbible_reference.md +++ b/docs/getbible_reference.md @@ -6,7 +6,11 @@ The `GetBibleReference` package is a Python library designed for efficiently ret - Returns well formed book-number, chatper-number, and verse array when given any scripture text reference. -## Installation +## Installation (pip) + +To install the package using pip, see [the documentation](https://git.vdm.dev/getBible/-/packages/pypi/getbible-librarian). + +## Installation (git) To install `GetBibleReference`, you need to clone the repository and install the package manually. Ensure you have Python 3.7 or higher installed. @@ -66,4 +70,3 @@ Contributions to the `GetBibleReference` class is welcome. Please ensure to foll ## License This project is licensed under the GNU GPL v2.0. See the LICENSE file for more details. - diff --git a/docs/getbible_scripture.md b/docs/getbible_scripture.md new file mode 100644 index 0000000..0eb88b7 --- /dev/null +++ b/docs/getbible_scripture.md @@ -0,0 +1,84 @@ +# GetBible Scripture + +The `GetBible` package is a Python library designed for efficiently retrieving scripture across various translations. + +## Features + +- Returns a selected range of referenced scripture passages. + +## Installation (pip) + +To install the package using pip, see [the documentation](https://git.vdm.dev/getBible/-/packages/pypi/getbible-librarian). + +## Installation (git) + +To install `GetBible`, you need to clone the repository and install the package manually. Ensure you have Python 3.7 or higher installed. + +```bash +git clone https://git.vdm.dev/getBible/librarian.git +cd librarian +pip install . +``` + +## Usage + +### Basic Usage + +```python +import json +from getbible import GetBible + +# Initialize the class +getbible = GetBible() + +# Get the scripture as JSON +scripture_json = getbible.scripture("Genesis 1:1") +print(scripture_json) # Outputs the JSON scripture as a string. + +# Get the scripture as dictionary +scripture_dict = getbible.select("Genesis 1:1") +print(json.dumps(scripture_dict, indent=4)) # Pretty-prints the dictionary. +``` + +### Using Translation Abbreviations + +When utilizing the `GetBible` class to look up a reference, you can use the lowercase abbreviations of the target translation: + +```python +import json +from getbible import GetBible + +# Initialize the class +getbible = GetBible() + +scripture = getbible.select("Genesis 1:1-5", 'aov') +print(json.dumps(scripture, indent=4)) # Pretty-prints the dictionary. +``` + +In this code snippet, `"aov"` is used as the abbreviation for the Afrikaans Ou Vertaaling. + +## Development and Testing + +To contribute or run tests, clone the repository and set up a virtual environment: + +```bash +git clone https://git.vdm.dev/getBible/librarian.git +cd reference +python -m venv venv +source venv/bin/activate # On Windows use `venv\Scripts\activate` +pip install -e . +``` + +Run tests using the standard unittest framework: + +```bash +python -m unittest tests.test_getbible +``` + +## Contributing + +Contributions to the `GetBible` class is welcome. Please ensure to follow the coding standards and write tests for new features. + +## License + +This project is licensed under the GNU GPL v2.0. See the LICENSE file for more details. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..941d8e7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests~=2.31.0 +setuptools>=65.5.1 \ No newline at end of file diff --git a/setup.py b/setup.py index 83de779..fe564c7 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,11 @@ from setuptools import setup, find_packages +with open('requirements.txt') as f: + required = f.read().splitlines() + setup( name="getBible-librarian", - version="0.1.0", + version="0.2.0", author="Llewellyn van der Merwe", author_email="getbible@vdm.io", description="A Python package to retrieving Bible references with ease.", @@ -13,7 +16,7 @@ setup( packages=find_packages(where="src"), package_data={"getbible": ["data/*.json"]}, include_package_data=True, - install_requires=[], + install_requires=required, classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", diff --git a/src/getbible/__init__.py b/src/getbible/__init__.py index ba48df3..d276229 100644 --- a/src/getbible/__init__.py +++ b/src/getbible/__init__.py @@ -1,3 +1,4 @@ from .getbible_book_number import GetBibleBookNumber from .getbible_reference import GetBibleReference from .getbible_reference import BookReference +from .getbible import GetBible diff --git a/src/getbible/getbible.py b/src/getbible/getbible.py new file mode 100644 index 0000000..7589dbc --- /dev/null +++ b/src/getbible/getbible.py @@ -0,0 +1,144 @@ +import os +import json +import requests +from getbible import GetBibleReference + + +class GetBible: + def __init__(self, repo_path="https://api.getbible.net", version='v2'): + """ + Initialize the GetBible class. + + :param repo_path: The repository path, which can be a URL or a local file path. + :param version: The version of the Bible repository. + """ + self.__get = GetBibleReference() + self.__repo_path = repo_path + self.__repo_version = version + self.__books_cache = {} + self.__chapters_cache = {} + # Determine if the repository path is a URL + self.__repo_path_url = self.__repo_path.startswith("http://") or self.__repo_path.startswith("https://") + + def select(self, reference, abbreviation='kjv'): + """ + Select and return Bible verses based on the reference and abbreviation. + + :param reference: The Bible reference (e.g., John 3:16). + :param abbreviation: The abbreviation for the Bible translation. + :return: dictionary of the selected Bible verses. + """ + self.__check_translation(abbreviation) + result = {} + references = reference.split(';') + for ref in references: + try: + reference = self.__get.ref(ref, abbreviation) + except ValueError: + raise ValueError(f"Invalid reference format.") + + for verse in reference.verses: + self.__set_verse(abbreviation, reference.book, reference.chapter, verse, result) + + return result + + def scripture(self, reference, abbreviation='kjv'): + """ + Select and return Bible verses based on the reference and abbreviation. + + :param reference: The Bible reference (e.g., John 3:16). + :param abbreviation: The abbreviation for the Bible translation. + :return: JSON string of the selected Bible verses. + """ + + return json.dumps(self.select(reference, abbreviation)) + + def __set_verse(self, abbreviation, book, chapter, verse, result): + """ + Set verse information into the result JSON. + + :param abbreviation: Bible translation abbreviation. + :param book: The book of the Bible. + :param chapter: The chapter number. + :param verse: The verse number. + :param result: The dictionary to store verse information. + """ + cache_key = f"{abbreviation}_{book}_{chapter}" + if cache_key not in self.__chapters_cache: + self.__chapters_cache[cache_key] = self.__retrieve_chapter_data(abbreviation, book, chapter) + chapter_data = self.__chapters_cache[cache_key] + verse_info = [v for v in chapter_data.get("verses", []) if str(v.get("verse")) == str(verse)] + if not verse_info: + raise ValueError(f"Verse {verse} not found in book {book}, chapter {chapter}.") + + if cache_key in result: + existing_verses = {str(v["verse"]) for v in result[cache_key].get("verses", [])} + new_verses = [v for v in verse_info if str(v["verse"]) not in existing_verses] + result[cache_key]["verses"].extend(new_verses) + else: + verse_data = chapter_data.copy() + verse_data["verses"] = verse_info + result[cache_key] = verse_data + + def __check_translation(self, abbreviation): + """ + Check if the given translation is available. + + :param abbreviation: The abbreviation of the Bible translation to check. + :raises FileNotFoundError: If the translation is not found. + """ + path = self.__generate_path(abbreviation, "books.json") + if abbreviation not in self.__books_cache: + self.__books_cache[abbreviation] = self.__fetch_data(path) + if self.__books_cache[abbreviation] is None: + raise FileNotFoundError(f"Translation ({abbreviation}) not found in this API.") + + def __generate_path(self, abbreviation, file_name): + """ + Generate the path or URL for a given file. + + :param abbreviation: Bible translation abbreviation. + :param file_name: Name of the file to fetch. + :return: Full path or URL to the file. + """ + if self.__repo_path_url: + return f"{self.__repo_path}/{self.__repo_version}/{abbreviation}/{file_name}" + else: + return os.path.join(self.__repo_path, self.__repo_version, abbreviation, file_name) + + def __fetch_data(self, path): + """ + Fetch data from either a URL or a local file path. + + :param path: The path or URL to fetch data from. + :return: The fetched data, or None if an error occurs. + """ + if self.__repo_path_url: + response = requests.get(path) + if response.status_code == 200: + return response.json() + else: + return None + else: + if os.path.isfile(path): + with open(path, 'r') as file: + return json.load(file) + else: + return None + + def __retrieve_chapter_data(self, abbreviation, book, chapter): + """ + Retrieve chapter data for a given book and chapter. + + :param abbreviation: Bible translation abbreviation. + :param book: The book of the Bible. + :param chapter: The chapter number. + :return: Chapter data. + :raises FileNotFoundError: If the chapter data is not found. + """ + chapter_file = f"{str(book)}/{chapter}.json" if self.__repo_path_url else os.path.join(str(book), + f"{chapter}.json") + chapter_data = self.__fetch_data(self.__generate_path(abbreviation, chapter_file)) + if chapter_data is None: + raise FileNotFoundError(f"File {abbreviation}/{book}/{chapter}.json does not exist.") + return chapter_data diff --git a/tests/test_getbible.py b/tests/test_getbible.py new file mode 100644 index 0000000..aecc758 --- /dev/null +++ b/tests/test_getbible.py @@ -0,0 +1,71 @@ +import unittest +import json +from getbible import GetBible + + +class TestGetBible(unittest.TestCase): + + def setUp(self): + self.getbible = GetBible() + + def test_valid_reference(self): + actual_result = json.loads(self.getbible.scripture('Gen 1:2-7', 'kjv')) + expected_result = { + "kjv_1_1": {"translation": "King James Version", "abbreviation": "kjv", "lang": "en", "language": "English", + "direction": "LTR", "encoding": "UTF-8", "book_nr": 1, "book_name": "Genesis", "chapter": 1, + "name": "Genesis 1", "verses": [{"chapter": 1, "verse": 2, "name": "Genesis 1:2", + "text": "And the earth was without form and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters."}, + {"chapter": 1, "verse": 3, "name": "Genesis 1:3", + "text": "And God said, Let there be light: and there was light."}, + {"chapter": 1, "verse": 4, "name": "Genesis 1:4", + "text": "And God saw the light, that it was good: and God divided the light from the darkness."}, + {"chapter": 1, "verse": 5, "name": "Genesis 1:5", + "text": "And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day."}, + {"chapter": 1, "verse": 6, "name": "Genesis 1:6", + "text": "And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters."}, + {"chapter": 1, "verse": 7, "name": "Genesis 1:7", + "text": "And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so."}]}} + self.assertEqual(actual_result, expected_result, "Failed to find 'Gen 1:2-7' scripture.") + + def test_valid_reference_cns(self): + actual_result = json.loads(self.getbible.scripture('创世记1:2-7', 'cns')) + expected_result = { + "cns_1_1": {"translation": "NCV Simplified", "abbreviation": "cns", "lang": "zh-Hans", + "language": "Chinese", + "direction": "LTR", "encoding": "UTF-8", "book_nr": 1, "book_name": "\ufeff\u521b\u4e16\u8bb0", + "chapter": 1, "name": "\ufeff\u521b\u4e16\u8bb0 1", "verses": [ + {"chapter": 1, "verse": 2, "name": "\ufeff\u521b\u4e16\u8bb0 1:2", + "text": "\u5730\u662f\u7a7a\u865a\u6df7\u6c8c\uff1b\u6df1\u6e0a\u4e0a\u4e00\u7247\u9ed1\u6697\uff1b\u3000\u795e\u7684\u7075\u8fd0\u884c\u5728\u6c34\u9762\u4e0a\u3002 "}, + {"chapter": 1, "verse": 3, "name": "\ufeff\u521b\u4e16\u8bb0 1:3", + "text": "\u795e\u8bf4\uff1a\u201c\u8981\u6709\u5149\uff01\u201d\u5c31\u6709\u4e86\u5149\u3002 "}, + {"chapter": 1, "verse": 4, "name": "\ufeff\u521b\u4e16\u8bb0 1:4", + "text": "\u795e\u770b\u5149\u662f\u597d\u7684\uff0c\u4ed6\u5c31\u628a\u5149\u6697\u5206\u5f00\u4e86\u3002 "}, + {"chapter": 1, "verse": 5, "name": "\ufeff\u521b\u4e16\u8bb0 1:5", + "text": "\u795e\u79f0\u5149\u4e3a\u663c\uff0c\u79f0\u6697\u4e3a\u591c\u3002\u6709\u665a\u4e0a\uff0c\u6709\u65e9\u6668\uff1b\u8fd9\u662f\u7b2c\u4e00\u65e5\u3002 "}, + {"chapter": 1, "verse": 6, "name": "\ufeff\u521b\u4e16\u8bb0 1:6", + "text": "\u795e\u8bf4\uff1a\u201c\u4f17\u6c34\u4e4b\u95f4\u8981\u6709\u7a79\u82cd\uff0c\u628a\u6c34\u548c\u6c34\u5206\u5f00\uff01\u201d\u4e8b\u5c31\u8fd9\u6837\u6210\u4e86\u3002 "}, + {"chapter": 1, "verse": 7, "name": "\ufeff\u521b\u4e16\u8bb0 1:7", + "text": "\u795e\u9020\u4e86\u7a79\u82cd\uff0c\u628a\u7a79\u82cd\u4ee5\u4e0b\u7684\u6c34\u548c\u7a79\u82cd\u4ee5\u4e0a\u7684\u6c34\u5206\u5f00\u4e86\u3002 "}]}} + self.assertEqual(actual_result, expected_result, "Failed to find '创世记1:2-7' scripture.") + + def test_valid_multiple_reference_aov(self): + actual_result = json.loads(self.getbible.scripture('Ge1:1;Jn1:1;1Jn1:1', 'aov')) + expected_result = { + "aov_1_1": {"translation": "Ou Vertaling", "abbreviation": "aov", "lang": "af", "language": "Afrikaans", + "direction": "LTR", "encoding": "UTF-8", "book_nr": 1, "book_name": "Genesis", "chapter": 1, + "name": "Genesis 1", "verses": [{"chapter": 1, "verse": 1, "name": "Genesis 1:1", + "text": "In die begin het God die hemel en die aarde geskape. "}]}, + "aov_43_1": {"translation": "Ou Vertaling", "abbreviation": "aov", "lang": "af", "language": "Afrikaans", + "direction": "LTR", "encoding": "UTF-8", "book_nr": 43, "book_name": "Johannes", "chapter": 1, + "name": "Johannes 1", "verses": [{"chapter": 1, "verse": 1, "name": "Johannes 1:1", + "text": "In die begin was die Woord, en die Woord was by God, en die Woord was God. "}]}, + "aov_62_1": {"translation": "Ou Vertaling", "abbreviation": "aov", "lang": "af", "language": "Afrikaans", + "direction": "LTR", "encoding": "UTF-8", "book_nr": 62, "book_name": "1 Johannes", + "chapter": 1, "name": "1 Johannes 1", "verses": [ + {"chapter": 1, "verse": 1, "name": "1 Johannes 1:1", + "text": "Wat van die begin af was, wat ons gehoor het, wat ons met ons o\u00eb gesien het, wat ons aanskou het en ons hande getas het aangaande die Woord van die lewe \u2014 "}]}} + self.assertEqual(actual_result, expected_result, "Failed to find 'Ge1:1;Jn1:1;1Jn1:1' scripture.") + + +if __name__ == '__main__': + unittest.main()