def __init__(self, sourceFolder, givenName, encoding='utf-8') -> None: """ Constructor: just sets up the XML Bible file converter object. """ # Setup and initialise the base class first dPrint( 'Quiet', debuggingThisModule, "OpenSongXMLBible( {}, {}, {} )".format(sourceFolder, givenName, encoding)) Bible.__init__(self) self.objectNameString = 'OpenSong XML Bible object' self.objectTypeString = 'OpenSong' # Now we can set our object variables self.sourceFolder, self.givenName, self.encoding = sourceFolder, givenName, encoding self.sourceFilepath = os.path.join(self.sourceFolder, self.givenName) self.XMLTree = None # Will hold the XML data # Get the data tables that we need for proper checking #self.ISOLanguages = ISO_639_3_Languages().loadData() self.genericBOS = BibleOrganisationalSystem('GENERIC-KJV-66-ENG') # Do a preliminary check on the readability of our file if not os.access(self.sourceFilepath, os.R_OK): vPrint( 'Quiet', debuggingThisModule, "OpenSongXMLBible: File {!r} is unreadable".format( self.sourceFilepath)) self.name = self.givenName
def fetchAllVersions(self): """ Download the version lists from FCBH. This can be quite slow. Populates self.versionList (323 entries as of 2014-10) Each list entry is a dictionary, e.g. {'version_name': '', 'version_code': 'ABB', 'english_name': ''} {'version_name': '', 'version_code': 'ABM', 'english_name': ''} {'version_name': '', 'version_code': 'ABS', 'english_name': ''} … {'version_name': 'Biblia de América', 'version_code': 'BDA', 'english_name': ' Biblia de America'} {'version_name': 'Hermanos Libres del Ecuador', 'version_code': 'HLE', 'english_name': ' Hermanos Libres del Ecuador'} {'version_name': '1545 Luther Bibel', 'version_code': 'L45', 'english_name': '1545 Luther Bibel'} … {'version_name': 'Yessan-Mayo Yamano Version', 'version_code': 'YYV', 'english_name': 'Yessan-Mayo Yamano Version'} {'version_name': 'Yessan-Mayo Yawu', 'version_code': 'YWV', 'english_name': 'Yessan-Mayo Yawu'} {'version_name': 'Ze Zoo Zersion', 'version_code': 'ZZQ', 'english_name': 'Ze Zoo Zersion'} """ fnPrint(debuggingThisModule, "DBPBibles.fetchAllVersions()") vPrint('Info', debuggingThisModule, _("Downloading list of available versions from FCBH…")) if self.onlineVersion: # Get a list of available data sets self.versionList = self.getOnlineData( 'library/version' ) # Get an alphabetically ordered list of dictionaries -- one for each version dPrint('Quiet', debuggingThisModule, " versionList", len(self.versionList)) #, self.versionList ) return self.versionList
def fetchAllLanguages(self): """ Download the language lists from FCBH. This can be quite slow. Populates self.languageList (1733 entries as of 2014-10) Each list entry is a dictionary, e.g. {'language_family_code': 'CTD', 'language_name': 'Zokam', 'language_iso_name': 'Tedim Chin', 'english_name': 'Zokam', 'language_code': 'CTD', 'language_iso_2B': '', 'language_iso': 'ctd', 'language_iso_1': '', 'language_iso_2T': ''} {'language_family_code': 'ZOS', 'language_name': 'Zoque de Francisco León', 'language_iso_name': 'Francisco León Zoque', 'english_name': 'Zoque de Francisco Leon', 'language_code': 'ZOS', 'language_iso_2B': '', 'language_iso': 'zos', 'language_iso_1': '', 'language_iso_2T': ''} {'language_family_code': 'GND', 'language_name': 'Zulgo', 'language_iso_name': 'Zulgo-Gemzek', 'english_name': 'Zulgo', 'language_code': 'GND', 'language_iso_2B': '', 'language_iso': 'gnd', 'language_iso_1': '', 'language_iso_2T': ''} {'language_family_code': 'ZUN', 'language_name': 'Zuni', 'language_iso_name': 'Zuni', 'english_name': 'Zuni', 'language_code': 'ZUN', 'language_iso_2B': 'zun', 'language_iso': 'zun', 'language_iso_1': '', 'language_iso_2T': 'zun'} """ fnPrint(debuggingThisModule, "DBPBibles.fetchAllLanguages()") vPrint('Info', debuggingThisModule, _("Downloading list of available languages from FCBH…")) if self.onlineVersion: # Get a list of available data sets self.languageList = self.getOnlineData( "library/language" ) # Get an alphabetically ordered list of dictionaries -- one for each language dPrint('Quiet', debuggingThisModule, " languageList", len(self.languageList)) #, self.languageList ) return self.languageList
def validateWithLint( self ): """ On a Linux system, runs the xmllint program to validate the XML file. """ checkProgramOutputString = checkProgramErrorOutputString = None parameters = [ '/usr/bin/xmllint', '--noout', self.sourceFilepath ] if self.schemaFilepath: parameters = [ '/usr/bin/xmllint', '--noout', '--schema', self.schemaFilepath, self.sourceFilepath ] checkProcess = subprocess.Popen( parameters, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) checkProgramOutputBytes, checkProgramErrorOutputBytes = checkProcess.communicate() if checkProgramOutputBytes: checkProgramOutputString = checkProgramOutputBytes.decode( encoding='utf-8', errors='replace' ) if checkProgramErrorOutputBytes: checkProgramErrorOutputString = checkProgramErrorOutputBytes.decode( encoding='utf-8', errors='replace' ) if checkProcess.returncode != 0: vPrint( 'Normal', debuggingThisModule, " WARNING: xmllint gave an error on the {} XML file: {} = {}" \ .format( self.sourceFilepath, checkProcess.returncode, xmllintError[checkProcess.returncode] ) ) self.validatedWithLint = False else: vPrint( 'Info', debuggingThisModule, " xmllint validated the xml file {}.".format( self.sourceFilepath ) ) self.validatedWithLint = True dPrint( 'Quiet', debuggingThisModule, "cPOS = {!r}".format( checkProgramOutputString ) ) dPrint( 'Quiet', debuggingThisModule, "cPEOS = {!r}".format( checkProgramErrorOutputString ) ) return self.validatedWithLint, checkProgramOutputString, checkProgramErrorOutputString
def main() -> None: """ Reorder songs by title (\s line in song record -- assumed to always be the second line in the record). """ BibleOrgSysGlobals.introduceProgram(__name__, programNameVersion, LAST_MODIFIED_DATE) # Read our sample data songsInputFilepath = os.path.join( testFolder, testFile) # Relative to module call, not cwd vPrint('Quiet', debuggingThisModule, _("Loading songs from {}…").format(songsInputFilepath)) songs = SFMFile.SFMRecords() # Left the four default parameters at the end of the next line so you can see what's available songs.read(songsInputFilepath, key='c', ignoreSFMs=None, ignoreEntries=None, changePairs=None, encoding='utf-8') vPrint('Normal', debuggingThisModule, _(" {} songs loaded").format(len(songs.records))) vPrint('Never', debuggingThisModule, songs) # Extract the information out of the file that we want to use for sorting # (We get the \s field, plus keep track of the index of each record) keyPairs = [] for j, songRecord in enumerate(songs.records): dPrint('Never', debuggingThisModule, "songRecord", songRecord) sFieldData = songRecord[ 1] # Get the second line of the song record (assumed to be the \s or title line ) assert sFieldData[ 0] == 's' # This is a 2-tuple of marker (without backslash) and marker contents keyPairs.append( (sFieldData[1], j) ) # Store the contents of the \s field, along with the index of this record dPrint('Never', debuggingThisModule, "keyPairs", keyPairs) # Now we sort the records by the \s field and write them out to a new file in the new, sorted order songsOutputFilepath = os.path.join( outputFolder, testFile) # Relative to module call, not cwd vPrint('Quiet', debuggingThisModule, "Writing reordered songs to {}…".format(songsOutputFilepath)) with open(songsOutputFilepath, 'wt') as outputFile: for k, keyPair in enumerate(sorted(keyPairs)): vPrint('Never', debuggingThisModule, "keyPair", keyPair) outputFile.write( '\n\\c {}\n'.format(k + 1) ) # Output our new (numbered) c line at the start of the record songRecord = songs.records[ keyPair[1]] # Get the record (song) that we need for s, songLine in enumerate(songRecord): vPrint('Never', debuggingThisModule, "songLine", s, songLine) if s == 0: continue # skip old c line outputFile.write('\\{} {}\n'.format(*songLine)) vPrint('Normal', debuggingThisModule, " {} songs written".format(k + 1)) vPrint('Quiet', debuggingThisModule, "{} finished.".format(programNameVersion))
def fetchAllEnglishTextVolumes(self): """ Download the volume lists from FCBH if necessary. (This can be quite slow.) Populates self.EnglishVolumeNameDict (847 entries as of 2014-10) Dictionary keys are version names, entries are a list of indexes to self.volumeList, e.g. 'Popoloca San Juan Atzingo 1982 Edition' [1143] 'Zokam 1994 Zokam International Version' [334] 'ಕನ್ನಡ Easy-to-Read Version' [413] … 'English 2001 English Standard' [393, 395] 'English English Version for the Deaf' [396, 397] 'English King James' [399, 401, 403, 405] 'English 1995 Edition' [406, 407] 'English 1986 New Life Version (Easy to Read)' [408] 'English World English Bible' [410, 411] … 'Español La Biblia de las Americas' [1302, 1303] 'Mam, Northern 1993 Edition' [825, 826] 'Русский 1876 Synodal Bible' [1246, 1247] """ fnPrint(debuggingThisModule, "DBPBibles.fetchAllEnglishTextVolumes()") vPrint('Info', debuggingThisModule, _("Creating list of available English text volumes from FCBH…")) if self.volumeList is None: self.fetchAllVolumes() self.EnglishVolumeNameDict = {} if self.volumeList: # Create a list of resource types for j, volume in enumerate(self.volumeList): assert volume['language_family_code'] if volume['language_family_code'] == 'ENG': assert volume['volume_name'] ourName = '{}: {}'.format(volume['version_code'], volume['volume_name']) #ourName = volume['volume_name'] assert volume['media'] and volume['delivery'] and volume[ 'collection_code'] if volume['media'] == 'text': if 'web' in volume['delivery']: self.EnglishVolumeNameDict[ourName] = volume[ 'dam_id'][: 6] # Just remember the 6-character damRoot #if ourName in self.EnglishVolumeNameDict: self.EnglishVolumeNameDict[ourName].append( j ) #else: self.EnglishVolumeNameDict[ourName] = [j] else: vPrint('Info', debuggingThisModule, "No web delivery in", repr(ourName), "only", volume['delivery']) elif volume['media'] not in ('audio', 'video'): vPrint('Quiet', debuggingThisModule, "No text in", ourName, volume['media']) dPrint( 'Quiet', debuggingThisModule, "EnglishVolumeNameDict", len(self.EnglishVolumeNameDict)) #, self.EnglishVolumeNameDict ) return self.EnglishVolumeNameDict
def fetchAllBibles(self): """ Download the Bible lists from DCS. This can be quite slow. """ fnPrint(debuggingThisModule, "DCSBibles.fetchAllBibles()") limit = 500 # Documentation says 50, but larger numbers seem to work ok vPrint( 'Normal', debuggingThisModule, f"Downloading list of available Bibles from DCS ({limit} at a time)…" ) if self.onlineVersion: # Get a list of available data sets self.BibleList = [] # Does a case-insensitive search for searchText in ('ULT', 'UST', 'Bible', 'ULB', 'UDB'): # 7,227 if these are all included!!! pageNumber = 1 while True: if BibleOrgSysGlobals.verbosityLevel > 0: vPrint('Quiet', debuggingThisModule, f" Getting '{searchText}' page {pageNumber}…") resultDict = self.getOnlineData( f'repos/search?q={searchText}&page={pageNumber}&limit={limit}' ) #dPrint( 'Quiet', debuggingThisModule, f" Result {type(resultDict)} {len(resultDict)} = {resultDict}" ) # resultDict should be a dict of length 2 with keys 'ok'(=True) and 'data' assert resultDict and isinstance( resultDict, dict) and len(resultDict) == 2 \ and resultDict['ok']==True if not resultDict['data']: break # no more data if BibleOrgSysGlobals.verbosityLevel > 1: vPrint('Quiet', debuggingThisModule, f" Got {len(resultDict['data'])} entries") self.BibleList.extend(resultDict['data']) if pageNumber > 1 \ and len(resultDict['data']) < limit: # must be finished break pageNumber += 1 dPrint('Quiet', debuggingThisModule, " BibleList", len(self.BibleList), self.BibleList) return self.BibleList
def getOrganisationalSystemValue(self, valueName): """ Gets a value for the system. """ #dPrint( 'Quiet', debuggingThisModule, "getOrganisationalSystemValue( {} )".format( repr(valueName) ) ) assert self.__dataDict assert valueName and isinstance(valueName, str) if valueName in self.__dataDict: return self.__dataDict[valueName] # else maybe we can find the value in a derived text #dPrint( 'Quiet', debuggingThisModule, "q0", self.getOrganisationalSystemName() ) for tryType in self.getMoreBasicTypes(): if 'usesText' in self.__dataDict: for trySystemName in self.__dataDict['usesText']: if isinstance(trySystemName, str): dPrint( 'Quiet', debuggingThisModule, "trySystemName for 'usesText' is a string: {!r}". format(trySystemName)) elif isinstance(trySystemName, list): #dPrint( 'Quiet', debuggingThisModule, "trySystemName for 'usesText' is a list: {!r}".format( trySystemName ) ) trySystemName = trySystemName[ 0] # Take the first string from the list #dPrint( 'Quiet', debuggingThisModule, "q1", "{} is trying usesText of {}".format(self.__systemName,trySystemName) ) result = self.__boss.getOrganisationalSystemValue( trySystemName, valueName) if result is not None: return result if 'derivedFrom' in self.__dataDict: trySystemName = self.__dataDict['derivedFrom'] if isinstance(trySystemName, str): dPrint( 'Quiet', debuggingThisModule, "trySystemName for 'derivedFrom' is a string: {!r}". format(trySystemName)) elif isinstance(trySystemName, list): #dPrint( 'Quiet', debuggingThisModule, "trySystemName for 'derivedFrom' is a list: {!r}".format( trySystemName ) ) trySystemName = trySystemName[ 0] # Take the first string from the list #dPrint( 'Quiet', debuggingThisModule, "q2", "{} is trying derivedFrom of {}".format(self.__systemName,trySystemName) ) result = self.__boss.getOrganisationalSystemValue( trySystemName, valueName) if result is not None: return result # else we couldn't find it anywhere logging.error( _("{} Bible Organisational System has no {} specified (c)").format( self.getOrganisationalSystemName(), valueName))
def validate(self): """ """ from BibleOrgSys.Internals.InternalBibleInternals import BOS_ALL_ADDED_MARKERS for USFMMarker, styleData in self.dataDict.items(): dPrint('Verbose', debuggingThisModule, f"validate {USFMMarker} {styleData}") if USFMMarker.startswith('Heb') or USFMMarker.startswith( 'WordRef'): continue if USFMMarker in ('###', ): continue # ignore if USFMMarker[0] == '*': USFMMarker = USFMMarker[ 1:] # Remove any leading asterisk for the check if USFMMarker[-1] == '#': USFMMarker = USFMMarker[: -1] # Remove any trailing hash for the check #dPrint( 'Quiet', debuggingThisModule, USFMMarker ) assert USFMMarker in BibleOrgSysGlobals.loadedUSFMMarkers or USFMMarker in BOS_ALL_ADDED_MARKERS
def getOrganisationalSystemValue(valueName): """ Gets a value for the system. """ def getMoreBasicTypes(): """ Returns a list of more basic (original) types. """ ix = BibleOrgSysGlobals.ALLOWED_ORGANISATIONAL_TYPES.index( self.__dataDict["type"]) return BibleOrgSysGlobals.ALLOWED_ORGANISATIONAL_TYPES[ix + 1:] # end of getMoreBasicTypes #dPrint( 'Quiet', debuggingThisModule, "q0", valueName ) if valueName in self.__dataDict: return self.__dataDict[valueName] # else maybe we can find the value in a derived text #dPrint( 'Quiet', debuggingThisModule, "q1", self.getOrganisationalSystemName() ) for tryType in getMoreBasicTypes(): if 'usesText' in self.__dataDict: for trySystemName in self.__dataDict['usesText']: #dPrint( 'Quiet', debuggingThisModule, "q2", "{} is trying usesText of {}".format(self.__systemName,trySystemName) ) result = self.__boss.getOrganisationalSystemValue( trySystemName, valueName) #dPrint( 'Quiet', debuggingThisModule, " result is", result ) if result is not None: return result if 'derivedFrom' in self.__dataDict: trySystemName = self.__dataDict['derivedFrom'] if isinstance(trySystemName, str): dPrint( 'Quiet', debuggingThisModule, "trySystemName for 'derivedFrom' is a string: {!r}" .format(trySystemName)) elif isinstance(trySystemName, list): #dPrint( 'Quiet', debuggingThisModule, "trySystemName for 'derivedFrom' is a list: {!r}".format( trySystemName ) ) trySystemName = trySystemName[ 0] # Take the first string from the list #dPrint( 'Quiet', debuggingThisModule, "q3", "{} is trying derivedFrom of {}".format(self.__systemName,trySystemName) ) result = self.__boss.getOrganisationalSystemValue( trySystemName, valueName) #dPrint( 'Quiet', debuggingThisModule, " result is", result ) if result is not None: return result # else we couldn't find it anywhere logging.error( _("{} Bible Organisational System has no {} specified (b)"). format(self.__systemName, valueName))
def __init__(self, systemName) -> None: """ Constructor: """ def getOrganisationalSystemValue(valueName): """ Gets a value for the system. """ def getMoreBasicTypes(): """ Returns a list of more basic (original) types. """ ix = BibleOrgSysGlobals.ALLOWED_ORGANISATIONAL_TYPES.index( self.__dataDict["type"]) return BibleOrgSysGlobals.ALLOWED_ORGANISATIONAL_TYPES[ix + 1:] # end of getMoreBasicTypes #dPrint( 'Quiet', debuggingThisModule, "q0", valueName ) if valueName in self.__dataDict: return self.__dataDict[valueName] # else maybe we can find the value in a derived text #dPrint( 'Quiet', debuggingThisModule, "q1", self.getOrganisationalSystemName() ) for tryType in getMoreBasicTypes(): if 'usesText' in self.__dataDict: for trySystemName in self.__dataDict['usesText']: #dPrint( 'Quiet', debuggingThisModule, "q2", "{} is trying usesText of {}".format(self.__systemName,trySystemName) ) result = self.__boss.getOrganisationalSystemValue( trySystemName, valueName) #dPrint( 'Quiet', debuggingThisModule, " result is", result ) if result is not None: return result if 'derivedFrom' in self.__dataDict: trySystemName = self.__dataDict['derivedFrom'] if isinstance(trySystemName, str): dPrint( 'Quiet', debuggingThisModule, "trySystemName for 'derivedFrom' is a string: {!r}" .format(trySystemName)) elif isinstance(trySystemName, list): #dPrint( 'Quiet', debuggingThisModule, "trySystemName for 'derivedFrom' is a list: {!r}".format( trySystemName ) ) trySystemName = trySystemName[ 0] # Take the first string from the list #dPrint( 'Quiet', debuggingThisModule, "q3", "{} is trying derivedFrom of {}".format(self.__systemName,trySystemName) ) result = self.__boss.getOrganisationalSystemValue( trySystemName, valueName) #dPrint( 'Quiet', debuggingThisModule, " result is", result ) if result is not None: return result # else we couldn't find it anywhere logging.error( _("{} Bible Organisational System has no {} specified (b)"). format(self.__systemName, valueName)) # end of getOrganisationalSystemValue vPrint('Info', debuggingThisModule, _("Loading {!r} system").format(systemName)) assert systemName and isinstance(systemName, str) self.__boss = BibleOrganisationalSystems().loadData( ) # Doesn't reload the XML unnecessarily :) result = self.__boss.getOrganisationalSystem(systemName) if result is None: logging.critical( _("No {!r} system in Bible Organisational Systems").format( systemName)) self.__dataDict = self.__systemName = None del self return # else: self.__dataDict = result self.__systemName = systemName #dPrint( 'Quiet', debuggingThisModule, self.__dataDict ) # Now initialize the inherited classes bookOrderSystemName = self.getOrganisationalSystemValue( 'bookOrderSystem') versificationSystemName = self.getOrganisationalSystemValue( 'versificationSystem') punctuationSystemName = self.getOrganisationalSystemValue( 'punctuationSystem') booksNamesSystemName = self.getOrganisationalSystemValue( 'booksNamesSystem') dPrint( 'Never', debuggingThisModule, "Got organisation bits: BOS={}, VS={}, PS={}, BNS={}".format( bookOrderSystemName, versificationSystemName, punctuationSystemName, booksNamesSystemName)) if bookOrderSystemName and bookOrderSystemName != 'None' and bookOrderSystemName != 'Unknown': vPrint('Info', debuggingThisModule, "Uses {!r} book order system".format(bookOrderSystemName)) BibleBookOrderSystem.__init__(self, bookOrderSystemName) if versificationSystemName and versificationSystemName != 'None' and versificationSystemName != 'Unknown': vPrint( 'Info', debuggingThisModule, "Uses {!r} versification system".format( versificationSystemName)) BibleVersificationSystem.__init__(self, versificationSystemName) if punctuationSystemName and punctuationSystemName != 'None' and punctuationSystemName != 'Unknown': vPrint( 'Info', debuggingThisModule, "Uses {!r} punctuation system".format(punctuationSystemName)) BiblePunctuationSystem.__init__(self, punctuationSystemName) if booksNamesSystemName and booksNamesSystemName != 'None' and booksNamesSystemName != 'Unknown': vPrint('Info', debuggingThisModule, "Uses {!r} books name system".format(booksNamesSystemName)) BibleBooksNamesSystem.__init__( self, booksNamesSystemName, getOrganisationalSystemValue('includesBooks') ) # Does one extra step To create the input abbreviations # Do some cross-checking myBooks = getOrganisationalSystemValue('includesBooks') if myBooks is not None: for BBB in myBooks: if not BibleBookOrderSystem.containsBook(self, BBB): logging.error( _("Book {!r} is included in {} system but missing from {} book order system" ).format( BBB, self.__systemName, BibleBookOrderSystem.getBookOrderSystemName( self)))
def testSwB(SwFolderpath, SwModuleName=None): """ Crudely demonstrate and test the Sword Bible class """ from BibleOrgSys.Reference import VerseReferences vPrint('Normal', debuggingThisModule, _("Demonstrating the Sword Bible class…")) vPrint('Quiet', debuggingThisModule, " Test folder is {!r} {!r}".format(SwFolderpath, SwModuleName)) SwBible = SwordBible(SwFolderpath, SwModuleName) SwBible.loadBooks() # Load and process the file vPrint('Normal', debuggingThisModule, SwBible) # Just print a summary if BibleOrgSysGlobals.strictCheckingFlag: SwBible.check() #dPrint( 'Quiet', debuggingThisModule, UsfmB.books['GEN']._processedLines[0:40] ) SwBErrors = SwBible.getCheckResults() #dPrint( 'Quiet', debuggingThisModule, SwBErrors ) if BibleOrgSysGlobals.commandLineArguments.export: ##SwBible.toDrupalBible() SwBible.doAllExports(wantPhotoBible=False, wantODFs=False, wantPDFs=False) for reference in ( ('OT', 'GEN', '1', '1'), ('OT', 'GEN', '1', '3'), ('OT', 'PSA', '3', '0'), ('OT', 'PSA', '3', '1'), ('OT', 'DAN', '1', '21'), ('NT', 'MAT', '1', '1'), ('NT', 'MAT', '3', '5'), ('NT', 'MAT', '3', '8'), ('NT', 'JDE', '1', '4'), ('NT', 'REV', '22', '21'), ('DC', 'BAR', '1', '1'), ('DC', 'MA1', '1', '1'), ( 'DC', 'MA2', '1', '1', ), ): (T, BBB, C, V) = reference if T == 'OT' and len(SwBible) == 27: continue # Don't bother with OT references if it's only a NT if T == 'NT' and len(SwBible) == 39: continue # Don't bother with NT references if it's only a OT if T == 'DC' and len(SwBible) <= 66: continue # Don't bother with DC references if it's too small svk = VerseReferences.SimpleVerseKey(BBB, C, V) #dPrint( 'Quiet', debuggingThisModule, svk, SwBible.getVerseDataList( reference ) ) shortText = svk.getShortText() try: verseText = SwBible.getVerseText(svk) #dPrint( 'Quiet', debuggingThisModule, "verseText", verseText ) fullVerseText = SwBible.getVerseText(svk, fullTextFlag=True) except KeyError: verseText = fullVerseText = "Verse not available!" if BibleOrgSysGlobals.verbosityLevel > 1: dPrint('Quiet', debuggingThisModule, '') vPrint('Quiet', debuggingThisModule, reference, shortText, verseText) dPrint('Quiet', debuggingThisModule, ' {}'.format(fullVerseText)) return SwBible
def checkBookOrderSystem(self, thisSystemName, bookOrderSchemeToCheck): """ Check the given book order scheme against all the loaded systems. Create a new book order file if it doesn't match any. Returns the number of matched systems (which can also be used as a True/False "matched" flag). """ assert thisSystemName assert bookOrderSchemeToCheck assert self.__DataLists #dPrint( 'Quiet', debuggingThisModule, thisSystemName, bookOrderSchemeToCheck ) for BBB in bookOrderSchemeToCheck: if not BibleOrgSysGlobals.loadedBibleBooksCodes.isValidBBB(BBB): logging.error(f"Invalid '{BBB}' book code") matchedBookOrderSystemCodes = [] exactMatchCount, subsetMatchCount, systemMismatchCount, allErrors, errorSummary = 0, 0, 0, '', '' for bookOrderSystemCode in self.__DataLists: # Step through the various reference schemes if self.__DataLists[bookOrderSystemCode] == bookOrderSchemeToCheck: #dPrint( 'Quiet', debuggingThisModule, " {} exactly matches {!r} book order system".format( thisSystemName, bookOrderSystemCode ) ) exactMatchCount += 1 matchedBookOrderSystemCodes.append(bookOrderSystemCode) else: # it's not an exact match if len(self.__DataLists[bookOrderSystemCode]) == len( bookOrderSchemeToCheck ): # They're both contain the same NUMBER of books for BBB1, BBB2 in zip( self.__DataLists[bookOrderSystemCode], bookOrderSchemeToCheck): if BBB1 != BBB2: break thisError = " " + _( "Doesn't match '{0}' system (Both have {1} books, but {0} has {2} where {3} has {4})" ).format(bookOrderSystemCode, len(bookOrderSchemeToCheck), BBB1, thisSystemName, BBB2) errorSummary += ("\n" if errorSummary else "") + thisError else: thisError = " " + _( "Doesn't exactly match '{0}' system ({0} has {1} books whereas {2} has {3})" ).format(bookOrderSystemCode, len(self.__DataLists[bookOrderSystemCode]), thisSystemName, len(bookOrderSchemeToCheck)) allErrors += ("\n" if allErrors else "") + thisError #systemMismatchCount += 1 # look for a subset lastIndex, isSubset = -1, True for BBB in bookOrderSchemeToCheck: if not BBB in self.__DataLists[ bookOrderSystemCode]: # This book isn't even in the other system thisError = " " + _( "Can't match '{0}' system ({0} doesn't even have {1})" ).format(bookOrderSystemCode, BBB) allErrors += ("\n" if allErrors else "") + thisError isSubset = False break index = self.__DataLists[bookOrderSystemCode].index(BBB) #dPrint( 'Quiet', debuggingThisModule, BBB, index, lastIndex ) if index < lastIndex: # they must be in a different order thisError = " " + _( "Can't match '{0}' system ({0} has {1} in a different place)" ).format(bookOrderSystemCode, BBB) allErrors += ("\n" if allErrors else "") + thisError isSubset = False break lastIndex = index if isSubset: #dPrint( 'Quiet', debuggingThisModule, " {} is a subset of {!r} book order system".format( thisSystemName, bookOrderSystemCode ) ) subsetMatchCount += 1 matchedBookOrderSystemCodes.append(bookOrderSystemCode) systemMatchCount = exactMatchCount + subsetMatchCount # seems like we could improve this whole section of code systemMismatchCount = len(self.__DataLists) - systemMatchCount if systemMatchCount == 1: # What we hope for vPrint( 'Quiet', debuggingThisModule, " " + _("{} matched {} book order (with these {} books)").format( thisSystemName, matchedBookOrderSystemCodes[0], len(bookOrderSchemeToCheck))) dPrint('Quiet', debuggingThisModule, errorSummary) elif systemMatchCount == 0: # No matches vPrint( 'Quiet', debuggingThisModule, " " + _("{} mismatched {} book order systems (with these {} books)" ).format(thisSystemName, systemMismatchCount, len(bookOrderSchemeToCheck))) vPrint( 'Quiet', debuggingThisModule, allErrors if BibleOrgSysGlobals.debugFlag or BibleOrgSysGlobals.verbosityLevel > 2 else errorSummary) else: # Multiple matches vPrint( 'Quiet', debuggingThisModule, " " + _("{} matched {} book order system(s): {} (with these {} books)" ).format(thisSystemName, systemMatchCount, matchedBookOrderSystemCodes, len(bookOrderSchemeToCheck))) dPrint('Quiet', debuggingThisModule, errorSummary) if BibleOrgSysGlobals.commandLineArguments.export and not systemMatchCount: # Write a new file outputFilepath = os.path.join( os.path.dirname(__file__), 'DataFiles/', 'ScrapedFiles/', "BibleBookOrder_" + thisSystemName + '.xml') vPrint( 'Quiet', debuggingThisModule, _("Writing {} {} books to {}…").format( len(bookOrderSchemeToCheck), thisSystemName, outputFilepath)) with open(outputFilepath, 'wt', encoding='utf-8') as myFile: for n, BBB in enumerate(bookOrderSchemeToCheck): myFile.write(' <book id="{}">{}</book>\n'.format( n + 1, BBB)) myFile.write("</BibleBookOrderSystem>") return systemMatchCount
def fetchAllTextVolumes(self): """ Download the volume lists from FCBH if necessary. (This can be quite slow.) Populates self.volumeNameDict (847 entries as of 2014-10) Dictionary keys are version names, entries are a list of indexes to self.volumeList, e.g. 'Popoloca San Juan Atzingo 1982 Edition' [1143] 'Zokam 1994 Zokam International Version' [334] 'ಕನ್ನಡ Easy-to-Read Version' [413] … 'English 2001 English Standard' [393, 395] 'English English Version for the Deaf' [396, 397] 'English King James' [399, 401, 403, 405] 'English 1995 Edition' [406, 407] 'English 1986 New Life Version (Easy to Read)' [408] 'English World English Bible' [410, 411] … 'Español La Biblia de las Americas' [1302, 1303] 'Mam, Northern 1993 Edition' [825, 826] 'Русский 1876 Synodal Bible' [1246, 1247] """ fnPrint(debuggingThisModule, "DBPBibles.fetchAllTextVolumes()") vPrint('Info', debuggingThisModule, _("Creating list of available text volumes from FCBH…")) if self.volumeList is None: self.fetchAllVolumes() self.volumeNameDict = {} if self.volumeList: # Create a list of resource types for j, volume in enumerate(self.volumeList): assert volume['language_name'] and volume['volume_name'] ourName = '{} {}'.format(volume['language_name'], volume['volume_name']) assert volume['media'] and volume['delivery'] and volume[ 'collection_code'] if volume['media'] == 'text': if 'web' in volume['delivery']: #ourName= '{} {}'.format( volume['language_name'], volume['volume_name'] ) if ourName in self.volumeNameDict: #dPrint( 'Quiet', debuggingThisModule, "\nAlready have", ourName ) ##dPrint( 'Quiet', debuggingThisModule, "New", j, volume ) #ix = self.volumeNameDict[ourName] #oldVolume = self.volumeList[ix] ##dPrint( 'Quiet', debuggingThisModule, "Old", ix, oldVolume ) #assert len(volume) == len(oldVolume) #for someKey in volume: #if volume[someKey] != oldVolume[someKey]: #if someKey not in ('dam_id','fcbh_id','sku','updated_on','collection_name',): #dPrint( 'Quiet', debuggingThisModule, " ", someKey, volume[someKey], oldVolume[someKey] ) self.volumeNameDict[ourName].append(j) else: self.volumeNameDict[ourName] = [j] #else: vPrint( 'Quiet', debuggingThisModule, j, repr(volume['language_name']), repr(volume['volume_name']) ) else: vPrint('Info', debuggingThisModule, "No web delivery in", repr(ourName), "only", volume['delivery']) elif volume['media'] not in ('audio', 'video'): vPrint('Quiet', debuggingThisModule, "No text in", ourName, volume['media']) dPrint('Quiet', debuggingThisModule, " volumeNameDict", len(self.volumeNameDict)) #, self.volumeNameDict ) return self.volumeNameDict
def fetchAllVolumes(self): """ Download the volume lists from FCBH. This can be quite slow. Populates self.volumeList (1637 entries as of 2014-10) Each list entry is a dictionary, e.g. {'language_iso_1': '', 'collection_name': 'New Testament', 'language_family_iso_2B': '', 'created_on': '2011-00-00 00:00:00', 'sku': 'N1ZTQTBL', 'language_code': 'ZTQ', 'media_type': 'Non-Drama', 'delivery': ['mobile', 'web', 'subsplash'], 'num_sample_audio': '0', 'language_family_iso_2T': '', 'version_name': 'The Bible League', 'media': 'text', 'expiration': '0000-00-00', 'language_family_english': 'Zapoteco de Quioquitani', 'version_english': 'The Bible League', 'updated_on': '2014-09-12 22:28:08', 'language_family_name': 'Zapoteco de Quioquitani', 'language_iso_2T': '', 'language_family_code': 'ZTQ', 'volume_name': '2000 Edition', 'dbp_agreement': 'true', 'language_english': 'Zapoteco de Quioquitani', 'language_family_iso': 'ztq', 'dam_id': 'ZTQTBLN1ET', 'font': {'platforms': {'android': True, 'ios': True, 'web': True}, 'id': '12', 'files': {'zip': 'all.zip', 'ttf': 'font.ttf'}, 'name': 'Charis SIL', 'base_url': 'http://cloud.faithcomesbyhearing.com/fonts/Charis_SIL'}, 'resolution': [], 'audio_zip_path': 'ZTQTBLN1ET/ZTQTBLN1ET.zip', 'language_iso_2B': '', 'fcbh_id': 'ZTQTBLN1ET', 'status': 'live', 'language_family_iso_1': '', 'language_iso_name': 'Quioquitani-Quierí Zapotec', 'language_iso': 'ztq', 'language_name': 'Zapoteco de Quioquitani', 'right_to_left': 'false', 'num_art': '0', 'version_code': 'TBL', 'collection_code': 'NT'} {'language_iso_1': '', 'collection_name': 'New Testament', 'language_family_iso_2B': '', 'created_on': '2010-09-14 17:01:29', 'sku': 'N1ZTYTBL', 'language_code': 'ZTY', 'media_type': 'Non-Drama', 'delivery': ['mobile', 'web', 'web_streaming', 'streaming_url', 'mp3_cd', 'digital_download', 'bible_stick', 'subsplash'], 'num_sample_audio': '1', 'language_family_iso_2T': '', 'version_name': 'The Bible League', 'media': 'audio', 'expiration': '0000-00-00', 'language_family_english': 'Zapoteco de Yatee', 'version_english': 'The Bible League', 'updated_on': '2014-01-03 21:36:32', 'language_family_name': 'Zapoteco de Yatee', 'language_iso_2T': '', 'language_family_code': 'ZTY', 'volume_name': '2002 Edition', 'dbp_agreement': 'true', 'language_english': 'Zapoteco de Yatee', 'language_family_iso': 'zty', 'dam_id': 'ZTYTBLN1DA', 'font': None, 'resolution': [], 'audio_zip_path': 'ZTYTBLN1DA/ZTYTBLN1DA.zip', 'language_iso_2B': '', 'fcbh_id': 'ZTYTBLN1DA', 'status': 'live', 'language_family_iso_1': '', 'language_iso_name': 'Yatee Zapotec', 'language_iso': 'zty', 'language_name': 'Zapoteco de Yatee', 'right_to_left': 'false', 'num_art': '3', 'version_code': 'TBL', 'collection_code': 'NT'} {'language_iso_1': '', 'collection_name': 'New Testament', 'language_family_iso_2B': '', 'created_on': '2011-00-00 00:00:00', 'sku': 'N1ZTYTBL', 'language_code': 'ZTY', 'media_type': 'Non-Drama', 'delivery': ['mobile', 'web', 'subsplash'], 'num_sample_audio': '0', 'language_family_iso_2T': '', 'version_name': 'The Bible League', 'media': 'text', 'expiration': '0000-00-00', 'language_family_english': 'Zapoteco de Yatee', 'version_english': 'The Bible League', 'updated_on': '2014-09-12 22:28:08', 'language_family_name': 'Zapoteco de Yatee', 'language_iso_2T': '', 'language_family_code': 'ZTY', 'volume_name': '2002 Edition', 'dbp_agreement': 'true', 'language_english': 'Zapoteco de Yatee', 'language_family_iso': 'zty', 'dam_id': 'ZTYTBLN1ET', 'font': {'platforms': {'android': True, 'ios': True, 'web': True}, 'id': '12', 'files': {'zip': 'all.zip', 'ttf': 'font.ttf'}, 'name': 'Charis SIL', 'base_url': 'http://cloud.faithcomesbyhearing.com/fonts/Charis_SIL'}, 'resolution': [], 'audio_zip_path': 'ZTYTBLN1ET/ZTYTBLN1ET.zip', 'language_iso_2B': '', 'fcbh_id': 'ZTYTBLN1ET', 'status': 'live', 'language_family_iso_1': '', 'language_iso_name': 'Yatee Zapotec', 'language_iso': 'zty', 'language_name': 'Zapoteco de Yatee', 'right_to_left': 'false', 'num_art': '0', 'version_code': 'TBL', 'collection_code': 'NT'} """ fnPrint(debuggingThisModule, "DBPBibles.fetchAllVolumes()") vPrint('Info', debuggingThisModule, _("Downloading list of available volumes from FCBH…")) if self.onlineVersion: # Get a list of available data sets self.volumeList = self.getOnlineData( 'library/volume' ) # Get an alphabetically ordered list of dictionaries -- one for each volume dPrint('Quiet', debuggingThisModule, " volumeList", len(self.volumeList)) #, self.volumeList ) return self.volumeList
def loadBook(self, BBB: str): """ Load the requested book out of the SQLite3 database. """ fnPrint(debuggingThisModule, "loadBook( {} )".format(BBB)) assert self.preloadDone if BBB in self.books: dPrint('Quiet', debuggingThisModule, " {} is already loaded -- returning".format(BBB)) return # Already loaded if BBB in self.triedLoadingBook: logging.warning( "We had already tried loading MySwordBible {} for {}".format( BBB, self.name)) return # We've already attempted to load this book self.triedLoadingBook[BBB] = True self.bookNeedsReloading[BBB] = False if BibleOrgSysGlobals.verbosityLevel > 2 or BibleOrgSysGlobals.debugFlag: vPrint( 'Quiet', debuggingThisModule, _("MySwordBible: Loading {} from {}…").format( BBB, self.sourceFilepath)) #if self.suppliedMetadata['MySword']['OT'] and self.suppliedMetadata['MySword']['NT']: #testament, BBB = 'BOTH', 'GEN' #booksExpected, textLineCountExpected = 1, 31102 #elif self.suppliedMetadata['MySword']['OT']: #testament, BBB = 'OT', 'GEN' #booksExpected, textLineCountExpected = 1, 23145 #elif self.suppliedMetadata['MySword']['NT']: #testament, BBB = 'NT', 'MAT' #booksExpected, textLineCountExpected = 1, 7957 # Create the first book thisBook = BibleBook(self, BBB) thisBook.objectNameString = 'MySword Bible Book object' thisBook.objectTypeString = 'MySword' verseList = self.BibleOrganisationalSystem.getNumVersesList(BBB) numC, numV = len(verseList), verseList[0] nBBB = BibleOrgSysGlobals.loadedBibleBooksCodes.getReferenceNumber(BBB) C = V = 1 #bookCount = 0 ourGlobals = {} continued = ourGlobals['haveParagraph'] = False haveLines = False while True: self.cursor.execute( 'select Scripture from Bible where Book=? and Chapter=? and Verse=?', (nBBB, C, V)) try: row = self.cursor.fetchone() line = row[0] except TypeError: # This reference is missing (row is None) #dPrint( 'Quiet', debuggingThisModule, "something wrong at", BBB, C, V ) #if BibleOrgSysGlobals.debugFlag: halt #dPrint( 'Quiet', debuggingThisModule, row ) line = None #dPrint( 'Quiet', debuggingThisModule, nBBB, BBB, C, V, 'MySw file line is "' + line + '"' ) if line is None: logging.warning( "MySwordBible.load: Have missing verse line at {} {}:{}". format(BBB, C, V)) else: # line is not None if not isinstance(line, str): if 'encryption' in self.suppliedMetadata['MySword']: logging.critical( "MySwordBible.load: Unable to decrypt verse line at {} {}:{} {!r}" .format(BBB, C, V, line)) break else: logging.critical( "MySwordBible.load: Unable to decode verse line at {} {}:{} {!r} {}" .format(BBB, C, V, line, self.suppliedMetadata['MySword'])) elif not line: logging.warning( "MySwordBible.load: Found blank verse line at {} {}:{}" .format(BBB, C, V)) else: haveLines = True # Some modules end lines with \r\n or have it in the middle! # (We just ignore these for now) while line and line[-1] in '\r\n': line = line[:-1] if '\r' in line or '\n' in line: # (in the middle) logging.warning( "MySwordBible.load: Found CR or LF characters in verse line at {} {}:{}" .format(BBB, C, V)) line = line.replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ') #dPrint( 'Quiet', debuggingThisModule, "MySword.load", BBB, C, V, repr(line) ) handleRTFLine(self.name, BBB, C, V, line, thisBook, ourGlobals) V += 1 if V > numV: C += 1 if C <= numC: # next chapter only #thisBook.addLine( 'c', str(C) ) numV = verseList[C - 1] V = 1 else: # Save this book now if haveLines: vPrint('Info', debuggingThisModule, " MySword saving", BBB) self.stashBook(thisBook) #else: vPrint( 'Quiet', debuggingThisModule, "Not saving", BBB ) break if ourGlobals['haveParagraph']: thisBook.addLine('p', '') ourGlobals['haveParagraph'] = False
def USFMBookCompare(filepath1, filepath2, file1Name='file1', file2Name='file2'): """ """ vPrint('Info', debuggingThisModule, "\nUSFMBookCompare() for USFM Bible books") vPrint('Verbose', debuggingThisModule, " comparing {}".format(filepath1)) vPrint('Verbose', debuggingThisModule, " and {}".format(filepath2)) # Set up empty results dictionaries resultDict = {} resultDict['File1'], resultDict['File2'] = {}, {} resultDict['Same'], resultDict['Different'], resultDict[ 'Summary'] = {}, {}, {} # Note paths and folders resultDict['File1']['Filepath'], resultDict['File2'][ 'Filepath'] = filepath1, filepath2 resultDict['File1']['Folder'], resultDict['File1'][ 'Filename'] = os.path.split(filepath1) resultDict['File2']['Folder'], resultDict['File2'][ 'Filename'] = os.path.split(filepath2) if resultDict['File2']['Filename'] == resultDict['File1']['Filename']: resultDict['Same']['Filename'] = resultDict['File1']['Filename'] if resultDict['File2']['Folder'] == resultDict['File1']['Folder']: resultDict['Same']['Folder'] = resultDict['File1']['Folder'] # Note file dates and sizes s1, s2 = os.stat(filepath1), os.stat(filepath2) resultDict['File1']['Filesize'], resultDict['File2'][ 'Filesize'] = s1.st_size, s2.st_size if resultDict['File1']['Filesize'] == resultDict['File2']['Filesize']: resultDict['Same']['Filesize'] = resultDict['File1']['Filesize'] else: resultDict['Different']['Filesize'] = (resultDict['File1']['Filesize'], resultDict['File2']['Filesize']) if s1.st_size > s2.st_size: resultDict['Summary'][ 'Filesize'] = "{} is bigger (by {:,} bytes)".format( file1Name, s1.st_size - s2.st_size) elif s1.st_size < s2.st_size: resultDict['Summary'][ 'Filesize'] = "{} is bigger (by {:,} bytes)".format( file2Name, s2.st_size - s1.st_size) resultDict['File1']['ModifiedTimeStamp'], resultDict['File2'][ 'ModifiedTimeStamp'] = s1.st_mtime, s2.st_mtime if s1.st_mtime - s2.st_mtime > 1.0: resultDict['Summary']['ModifiedTime'] = "{} is newer".format(file1Name) elif s2.st_mtime - s1.st_mtime > 1.0: resultDict['Summary']['ModifiedTime'] = "{} is newer".format(file2Name) t1, t2 = datetime.fromtimestamp(s1.st_mtime), datetime.fromtimestamp( s2.st_mtime) resultDict['File1']['ModifiedDate'], resultDict['File2'][ 'ModifiedDate'] = t1.strftime('%Y-%m-%d'), t2.strftime('%Y-%m-%d') if resultDict['File1']['ModifiedDate'] == resultDict['File2'][ 'ModifiedDate']: resultDict['Same']['ModifiedDate'] = resultDict['File1'][ 'ModifiedDate'] else: resultDict['Different']['ModifiedDate'] = ( resultDict['File1']['ModifiedDate'], resultDict['File2']['ModifiedDate']) resultDict['File1']['ModifiedTime'], resultDict['File2'][ 'ModifiedTime'] = t1.strftime('%H:%M:%S'), t2.strftime('%H:%M:%S') if resultDict['File1']['ModifiedTime'] == resultDict['File2'][ 'ModifiedTime']: resultDict['Same']['ModifiedTime'] = resultDict['File1'][ 'ModifiedTime'] else: resultDict['Different']['ModifiedTime'] = ( resultDict['File1']['ModifiedTime'], resultDict['File2']['ModifiedTime']) # Read the files uf1, uf2 = USFMFile(), USFMFile() uf1.read(filepath1) uf2.read(filepath2) #dPrint( 'Quiet', debuggingThisModule, 'f1', uf1.lines ) #dPrint( 'Quiet', debuggingThisModule, 'f2', uf2.lines ) # Note line counts resultDict['File1']['LineCount'], resultDict['File2']['LineCount'] = len( uf1.lines), len(uf2.lines) if resultDict['File1']['LineCount'] == resultDict['File2']['LineCount']: resultDict['Same']['LineCount'] = resultDict['File1']['LineCount'] else: resultDict['Different']['LineCount'] = ( resultDict['File1']['LineCount'], resultDict['File2']['LineCount']) # Work through each file counting chapters and verses, etc. resultDict['File1']['IntroLineCount'] = resultDict['File2'][ 'IntroLineCount'] = 0 resultDict['File1']['ChapterMarkerCount'] = resultDict['File2'][ 'ChapterMarkerCount'] = 0 resultDict['File1']['VerseMarkerCount'] = resultDict['File2'][ 'VerseMarkerCount'] = 0 resultDict['File1']['HasContentCount'] = resultDict['File2'][ 'HasContentCount'] = 0 startedCVs = False lastC = lastV = 0 C, V = '-1', '-1' # So first/id line starts at -1:0 for marker, line in uf1.lines: #dPrint( 'Quiet', debuggingThisModule, '1', C, V, lastC, lastV, marker, line ) if marker == 'c': resultDict['File1']['ChapterMarkerCount'] += 1 C, V, lastV = line.strip(), '0', 0 try: intC = int(C) except ValueError: intC = -2 # invalid value startedCVs = True if intC != lastC + 1: if 'File1Chapters' not in resultDict[ 'Summary']: # only record the first one resultDict['Summary'][ 'File1Chapters'] = "{} has chapters out of order ({} after {})".format( file1Name, C, lastC) lastC = intC elif marker == 'v': resultDict['File1']['VerseMarkerCount'] += 1 V = line.strip().split()[0] if '-' in V: # it's a verse bridge V, V2 = V.split('-', 1) else: V2 = None try: intV = int(V) except ValueError: intV = -1 startedCVs = True # Some one chapter books don't include a chapter marker if intV != lastV + 1: if 'File1Verses' not in resultDict[ 'Summary']: # only record the first one resultDict['Summary'][ 'File1Verses'] = "{} has verses out of order ({}:{} after {}:{})".format( file1Name, C, V, C, lastV) if V2: lastV = int(V2) else: lastV = intV if not startedCVs: resultDict['File1']['IntroLineCount'] += 1 if line.strip(): resultDict['File1']['HasContentCount'] += 1 if '<<<<' in line or '====' in line or '>>>>' in line: if 'File1Conflicts' not in resultDict[ 'Summary']: # only record the first one resultDict['Summary'][ 'File1Conflicts'] = "{} may have a merge conflict around {}:{}".format( file1Name, C, V) startedCVs = False lastC = lastV = 0 C, V = '-1', '-1' # So first/id line starts at -1:0 for marker, line in uf2.lines: #dPrint( 'Quiet', debuggingThisModule, '1', C, V, lastC, lastV, marker, line ) if marker == 'c': resultDict['File2']['ChapterMarkerCount'] += 1 C, V, lastV = line.strip(), '0', 0 try: intC = int(C) except ValueError: intC = -2 # invalid value startedCVs = True if intC != lastC + 1: if 'File2Chapters' not in resultDict[ 'Summary']: # only record the first one resultDict['Summary'][ 'File2Chapters'] = "{} has chapters out of order ({} after {})".format( file2Name, C, lastC) lastC = intC elif marker == 'v': resultDict['File2']['VerseMarkerCount'] += 1 V = line.strip().split()[0] if '-' in V: # it's a verse bridge V, V2 = V.split('-', 1) else: V2 = None try: intV = int(V) except ValueError: intV = -1 startedCVs = True # Some one chapter books don't include a chapter marker if intV != lastV + 1: if 'File2Verses' not in resultDict[ 'Summary']: # only record the first one resultDict['Summary'][ 'File2Verses'] = "{} has verses out of order ({}:{} after {}:{})".format( file2Name, C, V, C, lastV) if V2: lastV = int(V2) else: lastV = intV if not startedCVs: resultDict['File2']['IntroLineCount'] += 1 if line.strip(): resultDict['File2']['HasContentCount'] += 1 if '<<<<' in line or '====' in line or '>>>>' in line: if 'File2Conflicts' not in resultDict[ 'Summary']: # only record the first one resultDict['Summary'][ 'File2Conflicts'] = "{} may have a merge conflict around {}:{}".format( file2Name, C, V) if resultDict['File1']['IntroLineCount'] == resultDict['File2'][ 'IntroLineCount']: resultDict['Same']['IntroLineCount'] = resultDict['File1'][ 'IntroLineCount'] else: resultDict['Different']['IntroLineCount'] = ( resultDict['File1']['IntroLineCount'], resultDict['File2']['IntroLineCount']) if resultDict['File1']['IntroLineCount'] > resultDict['File2'][ 'IntroLineCount']: difference = resultDict['File1']['IntroLineCount'] - resultDict[ 'File2']['IntroLineCount'] resultDict['Summary'][ 'IntroLineCount'] = "{} has {} more intro marker{}".format( file1Name, difference, '' if difference == 1 else 's') elif resultDict['File1']['IntroLineCount'] < resultDict['File2'][ 'IntroLineCount']: difference = resultDict['File2']['IntroLineCount'] - resultDict[ 'File1']['IntroLineCount'] resultDict['Summary'][ 'IntroLineCount'] = "{} has {} more intro marker{}".format( file2Name, difference, '' if difference == 1 else 's') if resultDict['File1']['ChapterMarkerCount'] == resultDict['File2'][ 'ChapterMarkerCount']: resultDict['Same']['ChapterMarkerCount'] = resultDict['File1'][ 'ChapterMarkerCount'] else: resultDict['Different']['ChapterMarkerCount'] = ( resultDict['File1']['ChapterMarkerCount'], resultDict['File2']['ChapterMarkerCount']) if resultDict['File1']['ChapterMarkerCount'] > resultDict['File2'][ 'ChapterMarkerCount']: difference = resultDict['File1']['ChapterMarkerCount'] - resultDict[ 'File2']['ChapterMarkerCount'] resultDict['Summary'][ 'ChapterMarkerCount'] = "{} has {} more chapter marker{}".format( file1Name, ) elif resultDict['File1']['ChapterMarkerCount'] < resultDict['File2'][ 'ChapterMarkerCount']: difference = resultDict['File2']['ChapterMarkerCount'] - resultDict[ 'File1']['ChapterMarkerCount'] resultDict['Summary'][ 'ChapterMarkerCount'] = "{} has {} more chapter marker{}".format( file2Name, difference, '' if difference == 1 else 's') if resultDict['File1']['VerseMarkerCount'] == resultDict['File2'][ 'VerseMarkerCount']: resultDict['Same']['VerseMarkerCount'] = resultDict['File1'][ 'VerseMarkerCount'] else: resultDict['Different']['VerseMarkerCount'] = ( resultDict['File1']['VerseMarkerCount'], resultDict['File2']['VerseMarkerCount']) if resultDict['File1']['VerseMarkerCount'] > resultDict['File2'][ 'VerseMarkerCount']: difference = resultDict['File1']['VerseMarkerCount'] - resultDict[ 'File2']['VerseMarkerCount'] resultDict['Summary'][ 'VerseMarkerCount'] = "{} has {} more verse marker{}".format( file1Name, difference, '' if difference == 1 else 's') elif resultDict['File1']['VerseMarkerCount'] < resultDict['File2'][ 'VerseMarkerCount']: difference = resultDict['File2']['VerseMarkerCount'] - resultDict[ 'File1']['VerseMarkerCount'] resultDict['Summary'][ 'VerseMarkerCount'] = "{} has {} more verse marker{}".format( file2Name, difference, '' if difference == 1 else 's') if resultDict['File1']['HasContentCount'] == resultDict['File2'][ 'HasContentCount']: resultDict['Same']['HasContentCount'] = resultDict['File1'][ 'HasContentCount'] else: resultDict['Different']['HasContentCount'] = ( resultDict['File1']['HasContentCount'], resultDict['File2']['HasContentCount']) if resultDict['File1']['HasContentCount'] > resultDict['File2'][ 'HasContentCount']: difference = resultDict['File1']['HasContentCount'] - resultDict[ 'File2']['HasContentCount'] resultDict['Summary'][ 'HasContentCount'] = "{} has {} more content line{}".format( file1Name, difference, '' if difference == 1 else 's') elif resultDict['File1']['HasContentCount'] < resultDict['File2'][ 'HasContentCount']: difference = resultDict['File2']['HasContentCount'] - resultDict[ 'File1']['HasContentCount'] resultDict['Summary'][ 'HasContentCount'] = "{} has {} more content line{}".format( file2Name, difference, '' if difference == 1 else 's') # Work through the files again comparing lines # Trying to resync if there's a different number of lines…NOT FINISHED YET XXXXXXXXXXXXXXX resultDict['Same']['SameMarkerCount'] = resultDict['Different'][ 'DifferentMarkerCount'] = 0 resultDict['Same']['SameLineCount'] = resultDict['Different'][ 'DifferentLineCount'] = 0 lineIndex = lineOffset = 0 startedCVs1 = startedCVs2 = False while True: if lineIndex >= resultDict['File1']['LineCount']: vPrint('Never', debuggingThisModule, "File1 done") break if lineIndex >= resultDict['File2']['LineCount']: vPrint('Never', debuggingThisModule, "File2 done") break (m1, l1), (m2, l2) = uf1.lines[lineIndex], uf2.lines[lineIndex + lineOffset] #dPrint( 'Quiet', debuggingThisModule, lineIndex, lineOffset, m1, m2 ) if m1 == m2: resultDict['Same']['SameMarkerCount'] += 1 else: dPrint('Quiet', debuggingThisModule, "Diff", m1, m2, l1, l2) resultDict['Different']['DifferentMarkerCount'] += 1 if m1 == m2 and l1 == l2: resultDict['Same']['SameLineCount'] += 1 else: dPrint('Quiet', debuggingThisModule, "Diff", m1, m2, l1, l2) resultDict['Different']['DifferentLineCount'] += 1 lineIndex += 1 # Clean up and return for something, value in list(resultDict['Different'].items()): if not value: del resultDict['Different'][something] return resultDict