PyPassage is a small Python module for working with bible passages/references. It can:
- render reference strings sensibly and non-ambiguously; e.g. returning "Ephesians 1" when Ephesians 1:1-1:23 was specified, because there are only 23 verses in that chapter;
- look up actual passage text using external API services;
- fill in missing information where possible; e.g. inferring that for the inputs of
book="EPH"
andstart_chapter=1
, the whole Ephesians 1 chapter (verses 1 to 23) was intended; - verify that a passage is valid; e.g. telling you that Ephesians 99 and Genesis 3:5-1:2 can't exist;
- add verses or chapters to the start or end of a passage, or truncate a passage to a given number of verses; such as for satisfying copyright restrictions; and
- count the number of verses in a passage.
PyPassage now supports multi-book passages, such as 'Psalms-Proverbs'.
from pypassage import Passage
p = Passage(book='Genesis', start_chapter=1, start_verse=1, end_chapter=2, end_verse=3)
Books may be specified as their full name (e.g. "Revelation"), a three-letter abbreviation (e.g. "Rev"), or the book number (e.g. 66). Passages with a different ending book are created using the end_book
parameter:
>>> str(Passage(book='Genesis', start_chapter=1, start_verse=1, end_chapter=22, end_verse=21, end_book='Rev'))
'Genesis-Revelation'
If you have a simple string with a bible verse, calling passages_from_string
will parse and
return a Passage object
>>> str(passages_from_string("Gen 2:4"))
'Genesis 2:4'
Not all fields need to be provided. You may for example specify a single verse, a single chapter, or even a complete book:
p_verse = Passage('2 Corinthians',4,7)
p_chapter = Passage('Romans',1)
p_book = Passage('Philippians')
Invalid passages will throw an InvalidPassageException on instantiation:
>>> p = Passage('Deu', -3)
Traceback (most recent call last):
...
pypassage.reference.InvalidPassageException
Nevertheless, a valid passage may easily be made invalid after instantiation. Thus to check validity, you may call is_valid()
:
>>> p = Passage('2Co',3,12,3,18)
>>> p.end_verse = 99
>>> p.is_valid()
False
String representations of the passage reference can be created by simply calling str
:
>>> str(Passage('John',1,1,1,18))
'John 1:1-18'
Abbreviated book names can be used:
>>> Passage('John',1,1,1,18).abbr()
'Jn 1:1-18'
Adding together passages will return a PassageCollection object, which in turn can generate useful reference strings:
>>> c = Passage('Joh',1) + Passage('Joh',3) + Passage('Heb',1,1,1,4)
>>> str(c)
'John 1, 3; Hebrews 1:1-4'
and where there might be ambiguity, chapters and verses are made explicit:
>>> from pypassage import PassageCollection
>>> PassageCollection(Passage('Eph',1),Passage('Gen',3,2),Passage('Gen',3,6),Passage('Gen',8),Passage('Mat',5)).abbr()
'Eph 1; Gn 3:2, 3:6, 8:1-22; Mt 5'
OSIS-formatted reference strings can also be obtained:
>>> Passage('Joh',1).osis_reference()
'John.1.1-John.1.51'
The number of verses in a passage may be calculated by calling len
:
>>> len(Passage('Gen'))
1533
Chapters and/or verses can be added to the end of a passage by using the PassageDelta class:
>>> from pypassage import PassageDelta
>>> str(Passage('Rom',3,21) + PassageDelta(verses=5))
'Romans 3:21-26'
>>> str(Passage('Rom',1,1) + PassageDelta(chapters=1, verses=10))
'Romans 1:1-2:11'
To add verses to the start to the passage, set passage_start=True:
>>> str(Passage('Rom',3,21) + PassageDelta(verses=2, passage_start=True))
'Romans 3:19-21'
A passage may be truncated if it exceeds a specific number of verses or proportion of the book:
>>> str(Passage('Rom').truncate(number_verses=200))
'Romans 1:1-8:14'
>>> str(Passage('Ephesians').truncate(proportion_of_book=0.5))
'Ephesians 1:1-4:12'
Both arguments may provided simultaneously (something that is particularly useful for complying with copyright restrictions). If neither are relevant, the same passage will be returned:
>>> a = Passage('Luke',9,23)
>>> b = a.truncate(number_verses=500,proportion_of_book=0.5)
>>> a is b
True
Passage text can be looked up, using the ESV API service:
>>> Passage('Gen',1,1).text(api_key="XXXX")
(' In the beginning, God created the heavens and the earth.\n\n', False)
Full HTML may be fetched, and a dictionary of custom options passed in:
>>> Passage('Gen',1,1).text(api_key="XXXX", html=True, options={"include-headings":"true"})
(u'<h3 id="p01001001_01-1">The Creation of the World</h3>\n<p id="p01001001_06-1" class="starts-chapter"><b class="chapter-num" id="v01001001-1">1:1 </b>In the beginning, God created the heavens and the earth.</p>\n', False)
Results are cached (for the same option set) by default using a simple in-memory object. Custom caches may easily be defined. Please refer to ESV usage restrictions to ensure you use retrieved text in an appropriate manner.
At this stage passage data is based only on the ESV bible, but data for additional translations may readily be added (and are welcomed to this project). In the future it is intended that this module will parse arbitrary passage strings, but at this stage book, chapter, and verse must be directly specified.
Sample code for Django integration is given in the opt/django/
folder. Submission of similar code for other frameworks is welcome!
I would love to hear how you've used PyPassage. Drop me a line: cameronoliver+pypassage@gmail.com