Skip to content

Commit 14134b4

Browse files
committed
lint/test/doc fixes
1 parent 5461a9d commit 14134b4

17 files changed

Lines changed: 762 additions & 1325 deletions

.pre-commit-config.yaml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,11 @@ repos:
3737
rev: v1.18.2
3838
hooks:
3939
- id: mypy
40-
args: ["--config-file", "pyproject.toml", "--ignore-missing-imports"]
41-
#args: [--strict, --ignore-missing-imports]
4240
- repo: https://github.com/sourcery-ai/sourcery
4341
rev: v1.40.1b10
4442
hooks:
4543
- id: sourcery
46-
# The best way to use Sourcery in a pre-commit hook:
47-
# * review only changed lines:
48-
# * omit the summary
4944
args: [--diff=git diff HEAD, --no-summary]
5045

51-
exclude: pythonbible/bible/.*/.*\.py$
46+
# The versions files are huge and generated automatically.
47+
exclude: pythonbible/bible/versions/.*\.py$

CHANGELOG.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.15.0] - 2025-11-11
11+
1012
### Added
1113

1214
- Added several new English version/translation Bibles:
@@ -39,12 +41,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3941

4042
### Changed
4143

42-
- Modified the header image url to be an absolute url so that it hopefully shows up in PyPI correctly.
4344
- **BREAKING CHANGE**: Modified the NormalizedReference class to allow start chapter, start verse, end chapter, and end verse to be None.
4445
- The parser has also been updated to set those values to None unless they are explicitly set in the reference string. As we added more version/translation Bible texts, we realized the differences in chapter and verse numbers between versions/translations was much greater than initially assumed. This change allows for more flexibility in handling those differences.
4546
- The formatter has also been updated to get the appropriate start chapter, start verse, end chapter, and end verse at format time rather than parse time.
4647

47-
## [0.14.0] - 2024-06-10
48+
## [0.14.0] - 2025-11-09
4849

4950
### Added
5051

@@ -191,7 +192,8 @@ The goal of this release was to address [Issue #90], and to make things related
191192

192193
## [0.0.1] - 2020-10-08
193194

194-
[unreleased]: https://github.com/avendesora/pythonbible/compare/v0.14.0...HEAD
195+
[unreleased]: https://github.com/avendesora/pythonbible/compare/v0.15.0...HEAD
196+
[0.15.0]: https://github.com/avendesora/pythonbible/compare/v0.14.0...v0.15.0
195197
[0.14.0]: https://github.com/avendesora/pythonbible/compare/v0.13.1...v0.14.0
196198
[0.13.1]: https://github.com/avendesora/pythonbible/compare/v0.13.0...v0.13.1
197199
[0.13.0]: https://github.com/avendesora/pythonbible/compare/v0.12.0...v0.13.0

docs/source/advanced_usage.rst

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Example: Obadiah 1 vs Genesis 1
3636
start_verse=1,
3737
end_chapter=1,
3838
end_verse=1,
39-
end_book=None
39+
end_book=<Book.OBADIAH: 31>
4040
)
4141

4242
If a reference like this was found for a non single chapter book, the number would be assumed to be a chapter number rather than a verse number.
@@ -56,7 +56,7 @@ If a reference like this was found for a non single chapter book, the number wou
5656
start_verse=1,
5757
end_chapter=1,
5858
end_verse=31,
59-
end_book=None
59+
end_book=<Book.GENESIS: 1>
6060
)
6161

6262
Rather than being interpreted as Genesis 1:1, this would be interpreted as Genesis 1:1-31.
@@ -81,7 +81,7 @@ Example: Philemon 3-6 vs Genesis 3-6
8181
start_verse=3,
8282
end_chapter=1,
8383
end_verse=6,
84-
end_book=None
84+
end_book=<Book.PHILEMON: 57>
8585
)
8686

8787
This is interpreted as Philemon 1:3-6. If a similar reference were encountered for a non single chapter book, both numbers would be assumed to be chapter numbers rather than verse numbers.
@@ -100,10 +100,10 @@ This is interpreted as Philemon 1:3-6. If a similar reference were encountered f
100100
NormalizedReference(
101101
book=<Book.GENESIS: 1>,
102102
start_chapter=3,
103-
start_verse=1,
103+
start_verse=None,
104104
end_chapter=6,
105-
end_verse=22,
106-
end_book=None
105+
end_verse=None,
106+
end_book=<Book.GENESIS: 1>
107107
)
108108

109109
Rather than being interpreted as Genesis 1:3-6, this would be interpreted as Genesis 3:1-6:22.
@@ -205,7 +205,7 @@ For example, "Genesis - Deuteronomy" vs "Genesis;Exodus;Numbers;Leviticus;Deuter
205205
:execution-count: 1
206206

207207
[
208-
NormalizedReference(book=<Book.GENESIS: 1>, start_chapter=1, start_verse=1, end_chapter=34, end_verse=12, end_book=<Book.DEUTERONOMY: 5>),
208+
NormalizedReference(book=<Book.GENESIS: 1>, start_chapter=None, start_verse=None, end_chapter=None, end_verse=None, end_book=<Book.DEUTERONOMY: 5>),
209209
]
210210

211211
If rather than using the range, the text specified each book of the Bible separated by a comma or semi-colon (or just about anything), then the result would be a list of five normalized references, one for each of the five books referenced.
@@ -219,11 +219,11 @@ If rather than using the range, the text specified each book of the Bible separa
219219
:execution-count: 2
220220

221221
[
222-
NormalizedReference(book=<Book.GENESIS: 1>, start_chapter=1, start_verse=1, end_chapter=50, end_verse=26, end_book=None),
223-
NormalizedReference(book=<Book.EXODUS: 2>, start_chapter=1, start_verse=1, end_chapter=40, end_verse=38, end_book=None),
224-
NormalizedReference(book=<Book.LEVITICUS: 3>, start_chapter=1, start_verse=1, end_chapter=27, end_verse=34, end_book=None),
225-
NormalizedReference(book=<Book.NUMBERS: 4>, start_chapter=1, start_verse=1, end_chapter=36, end_verse=13, end_book=None),
226-
NormalizedReference(book=<Book.DEUTERONOMY: 5>, start_chapter=1, start_verse=1, end_chapter=34, end_verse=12, end_book=None),
222+
NormalizedReference(book=<Book.GENESIS: 1>, start_chapter=None, start_verse=None, end_chapter=None, end_verse=None, end_book=<Book.GENESIS: 1>),
223+
NormalizedReference(book=<Book.EXODUS: 2>, start_chapter=None, start_verse=None, end_chapter=None, end_verse=None, end_book=<Book.EXODUS: 2>),
224+
NormalizedReference(book=<Book.LEVITICUS: 3>, start_chapter=None, start_verse=None, end_chapter=None, end_verse=None, end_book=<Book.LEVITICUS: 3>),
225+
NormalizedReference(book=<Book.NUMBERS: 4>, start_chapter=None, start_verse=None, end_chapter=None, end_verse=None, end_book=<Book.NUMBERS: 4>),
226+
NormalizedReference(book=<Book.DEUTERONOMY: 5>, start_chapter=None, start_verse=None, end_chapter=None, end_verse=None, end_book=<Book.DEUTERONOMY: 5>)
227227
]
228228

229229
That list can optionally be optimized by converting it to verse ids and then back into references if so desired.

docs/source/basic_usage.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ For example, given the text "The parable of the lost sheep is told in Matthew 18
2626
:execution-count: 1
2727

2828
[
29-
NormalizedReference(book=<Book.MATTHEW: 40>, start_chapter=18, start_verse=12, end_chapter=18, end_verse=14, end_book=None),
30-
NormalizedReference(book=<Book.LUKE: 42>, start_chapter=15, start_verse=3, end_chapter=15, end_verse=7, end_book=None)
29+
NormalizedReference(book=<Book.MATTHEW: 40>, start_chapter=18, start_verse=12, end_chapter=18, end_verse=14, end_book=<Book.MATTHEW: 40>),
30+
NormalizedReference(book=<Book.LUKE: 42>, start_chapter=15, start_verse=3, end_chapter=15, end_verse=7, end_book=<Book.LUKE: 42>)
3131
]
3232

3333
Converting References to Verse IDs
@@ -62,7 +62,7 @@ The conversion functionality would return the following tuple of verse id intege
6262
.. output-cell:: python
6363
:execution-count: 1
6464

65-
[1001001, 1001002, 1001003, 1001004]
65+
(1001001, 1001002, 1001003, 1001004)
6666

6767
Converting a List of References to a List of Verse IDs
6868
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -106,8 +106,8 @@ The conversion functionality would return the following list of normalized scrip
106106
:execution-count: 1
107107

108108
[
109-
NormalizedReference(book=<Book.MATTHEW: 40>, start_chapter=18, start_verse=12, end_chapter=18, end_verse=14. end_book=None),
110-
NormalizedReference(book=<Book.LUKE: 42>, start_chapter=15, start_verse=3, end_chapter=15, end_verse=7, end_book=None),
109+
NormalizedReference(book=<Book.MATTHEW: 40>, start_chapter=18, start_verse=12, end_chapter=18, end_verse=14, end_book=<Book.MATTHEW: 40>),
110+
NormalizedReference(book=<Book.LUKE: 42>, start_chapter=15, start_verse=3, end_chapter=15, end_verse=7, end_book=<Book.LUKE: 42>)
111111
]
112112

113113
Formatting Scripture References

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
author = "Nathan Patton"
2424

2525
# The full version, including alpha/beta/rc tags
26-
release = "0.14.0"
26+
release = "0.15.0"
2727

2828

2929
# -- General configuration ---------------------------------------------------

pyproject.toml

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module-name = "pythonbible"
1111

1212
[project]
1313
name = "pythonbible"
14-
version = "0.14.0"
14+
version = "0.15.0"
1515
description-file = "README.md"
1616
requires-python = ">=3.10"
1717
authors = [
@@ -117,24 +117,16 @@ ignore = [
117117
[tool.ruff.lint.per-file-ignores]
118118
"docs/source/_static/pythonbible-book-groups.ipynb" = ["E501", "T201"]
119119
"docs/source/conf.py" = ["A001", "E501"]
120-
"pythonbible/__init__.py" = ["F401"]
121-
"pythonbible/bible/bible.py" = ["PLR0913", "FBT"]
122-
"pythonbible/books.py" = ["ARG003", "ARG004", "PYI034"]
123-
"pythonbible/book_groups.py" = ["ARG003", "ARG004", "PYI034"]
124-
"pythonbible/counters/book_counter.py" = ["TCH001"]
125-
"pythonbible/counters/chapter_counter.py" = ["TCH001"]
126-
"pythonbible/counters/verse_counter.py" = ["TCH001"]
127-
"pythonbible/errors.py" = ["PLR0913"]
128-
"pythonbible/formatter.py" = ["A005", "ANN401", "F841", "FBT", "PLR0911"] # TODO - remove F841
129-
"pythonbible/parser.py" = ["A005", "PLR2004"]
120+
"pythonbible/bible/bible.py" = ["PLR0913", "FBT001", "FBT002"]
121+
"pythonbible/books.py" = ["ARG004", "PYI034"]
122+
"pythonbible/book_groups.py" = ["ARG004", "PYI034"]
123+
"pythonbible/formatter.py" = ["ANN401", "FBT001", "FBT002", "PLR0911"]
124+
"pythonbible/parser.py" = ["PLR2004"]
130125
"pythonbible/roman_numeral_util.py" = ["E741"]
131-
"pythonbible/versions.py" = ["ARG003", "ARG004", "PYI034"]
132-
"tests/*.py" = ["D100", "D103", "D104", "FBT003", "PLR2004", "S101", "TRY301"]
133-
"tests/conftest.py" = ["E501", "RUF"]
134-
"tests/errors_test.py" = ["PT017"]
126+
"pythonbible/versions.py" = ["ARG004", "PYI034"]
127+
"tests/*.py" = ["FBT003", "PLR2004", "S101", "TRY301"]
128+
"tests/docs/advanced_usage_test.py" = ["FBT001"]
129+
"tests/formatter/missing_file_handling_test.py" = ["SLF001"]
135130

136131
[tool.ruff.lint.isort]
137132
force-single-line = true
138-
139-
[tool.mypy]
140-
exclude = ["pythonbible/bible/asv/*", "pythonbible/bible/kjv/*", ".*_test.py"]

pythonbible/__init__.py

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from __future__ import annotations
1010

11-
__version__ = "0.14.0"
11+
__version__ = "0.15.0"
1212

1313
from .bible import add_bible
1414
from .bible import get_bible
@@ -49,3 +49,89 @@
4949
from .verses import get_verse_id
5050
from .verses import get_verse_number
5151
from .versions import Version
52+
53+
__all__ = [
54+
"BOOK_GROUPS",
55+
"Bible",
56+
"Book",
57+
"BookGroup",
58+
"InvalidBibleParserError",
59+
"InvalidBookError",
60+
"InvalidChapterError",
61+
"InvalidVerseError",
62+
"MissingBookFileError",
63+
"MissingVerseFileError",
64+
"NormalizedReference",
65+
"Version",
66+
"VersionMissingVerseError",
67+
"__version__",
68+
"add_bible",
69+
"convert_reference_to_verse_ids",
70+
"convert_references_to_verse_ids",
71+
"convert_verse_ids_to_references",
72+
"count_books",
73+
"count_chapters",
74+
"count_verses",
75+
"format_scripture_references",
76+
"format_scripture_text",
77+
"format_single_reference",
78+
"get_bible",
79+
"get_book_chapter_verse",
80+
"get_book_number",
81+
"get_chapter_number",
82+
"get_number_of_chapters",
83+
"get_number_of_verses",
84+
"get_references",
85+
"get_verse_id",
86+
"get_verse_number",
87+
"get_verse_text",
88+
"is_valid_book",
89+
"is_valid_chapter",
90+
"is_valid_reference",
91+
"is_valid_verse",
92+
"is_valid_verse_id",
93+
"normalize_reference",
94+
]
95+
# Reference the imported names so ruff/auto-fixes do not remove them as "unused".
96+
_ = (
97+
add_bible,
98+
get_bible,
99+
Bible,
100+
VersionMissingVerseError,
101+
BOOK_GROUPS,
102+
BookGroup,
103+
Book,
104+
convert_reference_to_verse_ids,
105+
convert_references_to_verse_ids,
106+
convert_verse_ids_to_references,
107+
count_books,
108+
count_chapters,
109+
count_verses,
110+
InvalidBibleParserError,
111+
InvalidBookError,
112+
InvalidChapterError,
113+
InvalidVerseError,
114+
MissingBookFileError,
115+
MissingVerseFileError,
116+
format_scripture_references,
117+
format_scripture_text,
118+
format_single_reference,
119+
get_verse_text,
120+
NormalizedReference,
121+
get_references,
122+
normalize_reference,
123+
is_valid_book,
124+
is_valid_chapter,
125+
is_valid_reference,
126+
is_valid_verse,
127+
is_valid_verse_id,
128+
get_book_chapter_verse,
129+
get_book_number,
130+
get_chapter_number,
131+
get_number_of_chapters,
132+
get_number_of_verses,
133+
get_verse_id,
134+
get_verse_number,
135+
Version,
136+
__version__,
137+
)

pythonbible/formatter.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,9 @@ def _does_reference_include_all_verses_in_end_book(
410410
reference: NormalizedReference,
411411
**kwargs: Any,
412412
) -> bool:
413+
if reference.start_chapter is None and reference.end_chapter is None:
414+
return True
415+
413416
end_book: Book = reference.end_book or reference.book
414417
max_chapters = _get_number_of_chapters(end_book, **kwargs)
415418

@@ -434,7 +437,6 @@ def format_scripture_text(verse_ids: list[int], **kwargs: Any) -> str:
434437
one_verse_per_paragraph: bool = kwargs.get("one_verse_per_paragraph", False)
435438
full_title: bool = kwargs.get("full_title", False)
436439
format_type: str = kwargs.get("format_type", "html")
437-
include_books: bool = kwargs.get("include_books", True)
438440
include_verse_numbers: bool = kwargs.get("include_verse_numbers", True)
439441
version: Version = kwargs.get("version", DEFAULT_VERSION)
440442

tests/bible_test.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
from typing import NoReturn
4+
35
import pytest
46

57
import pythonbible as bible
@@ -91,3 +93,59 @@ def test_get_long_title_init_version() -> None:
9193

9294
# Then the version is initialized and the long title is returned
9395
assert long_title == book.title
96+
97+
98+
def test_get_bible_import_failure_raises_missing_verse_file_error() -> None:
99+
# Choose a version that has files on disk but ensure it's not cached in BIBLES
100+
version = bible.Version.KING_JAMES
101+
102+
# Remove any existing cached bible for this version so the code will attempt to
103+
# import
104+
bible.bible.BIBLES.pop(version, None)
105+
106+
# Request a bible type that does not exist to force ModuleNotFoundError
107+
# in import_module
108+
with pytest.raises(pythonbible.errors.MissingVerseFileError):
109+
bible.get_bible(version, "this_bible_type_does_not_exist")
110+
111+
112+
def test_get_bible_import_module_raises_missing_verse_file() -> None:
113+
version = bible.Version.KING_JAMES
114+
# Ensure no cached entry so get_bible will attempt to import
115+
bible.bible.BIBLES.pop(version, None)
116+
117+
# Now calling get_bible should run the try import_module and hit the except,
118+
# which should raise MissingVerseFileError derived from ModuleNotFoundError.
119+
with pytest.raises(pythonbible.errors.MissingVerseFileError):
120+
bible.get_bible(version, "any_type")
121+
122+
123+
def test_get_bible_import_module_raises_module_not_found_in_module(
124+
monkeypatch: pytest.MonkeyPatch,
125+
) -> None:
126+
# Monkeypatch the import_module function used inside pythonbible.bible.get_bible
127+
version = bible.Version.KING_JAMES
128+
bible.bible.BIBLES.pop(version, None)
129+
130+
def raise_module_not_found(name: str, package: str | None = None) -> NoReturn:
131+
error_message = f"No module named '{name}' in package '{package}'"
132+
raise ModuleNotFoundError(error_message)
133+
134+
monkeypatch.setattr(bible.bible, "import_module", raise_module_not_found)
135+
136+
with pytest.raises(pythonbible.errors.MissingVerseFileError):
137+
bible.get_bible(version, "any_type")
138+
139+
140+
def test_get_bible_with_missing_version_files_raises_missing_verse_file_error() -> None:
141+
# Create a minimal version-like object with a value for which no folder exists
142+
class DummyVersion:
143+
value = "this_version_folder_does_not_exist"
144+
145+
# Ensure no cached entry exists for this dummy key
146+
bible.bible.BIBLES.pop(DummyVersion, None) # type: ignore[arg-type,call-overload]
147+
148+
# Calling get_bible should check _do_version_files_exist and raise
149+
# MissingVerseFileError
150+
with pytest.raises(pythonbible.errors.MissingVerseFileError):
151+
bible.get_bible(DummyVersion, "plain_text") # type: ignore[arg-type]

0 commit comments

Comments
 (0)