def realHarmonic(self,dist): qs = self.model().data(self.contextIndex, Qt.DisplayRole).toString() word = unicode(qs) # get python string wordLen = len(word) # save a few cycles in the test below harmList = [] for i in range(IMC.wordCensus.size()): word2 = unicode(IMC.wordCensus.getWord(i)) if dist >= abs(wordLen - len(word2)): # There's a chance of a match if dist >= edit_distance(word,word2): # test it harmList.append(word2) # one hit is on the word itself if 1 < len(harmList) : # got at least 1 other self.panelRef.tableModel.beginResetModel() self.panelRef.listFilter = harmList self.panelRef.tableModel.endResetModel() self.panelRef.rowCountLabel.setNum(self.panelRef.proxy.rowCount()) else: pqMsgs.infoMsg( "There are no words in edit distance {0} edit of {1}".format(dist,word) )
def similarWords(self): qch = QChar(u'-') qcp = QChar(u"'") wordOriginal = self.model().data(self.contextIndex, Qt.DisplayRole).toString() word = QString(wordOriginal) word.remove(qch) word.remove(qcp) h1list = [] for i in range(IMC.wordCensus.size()): word1 = IMC.wordCensus.getWord(i) word2 = QString(word1) # force a copy! word2.remove(qch) # otherwise this would affect the word word2.remove(qcp) # in the census list if 0 == word.compare(word2,Qt.CaseInsensitive): h1list.append(unicode(word1)) # one hit on word itself if 1 < len(h1list): # got at least 1 other self.panelRef.tableModel.beginResetModel() self.panelRef.listFilter = h1list self.panelRef.tableModel.endResetModel() self.panelRef.rowCountLabel.setNum(self.panelRef.proxy.rowCount()) else: pqMsgs.infoMsg("There are no words similar to {0}".format(unicode(wordOriginal)))
def checkForUpdates(): # Step one, read the code display for the master page = slurp('https://github.com/tallforasmurf/PPQT') if page is None: pqMsgs.warningMsg('Unable to contact Github', 'Perhaps try again later?') return # the embedded URLs usable. hit = reGetMasterSHA.search(page) if hit is None: pqMsgs.warningMsg('Github page format not as expected', 'Probable bug, update not available') return masterSHA = hit.group(1) page = re.sub(masterSHA, 'master', page) # Step three, make a list of all the "blobs" mentioned, which is just # all the committed modules, pqXXX.py and pqHelp.html. Ignoring the # extras -- the extras folder appears as a "tree" item and we could # follow it and list all the blobs extras/* but we are not. blobs = reBlobLine.findall(page) # blobs is a list of 4-tuples, the (/1, /2, /3, /4) from reBlobLine above # Now make a dict with 3-item values, # { modname:[ None, masterhash, masterURL] } where None will be filled # in with the local hash value shortly. blobTab = {} for blob in blobs: blobURL = u'https://raw.github.com' + blob[0] + u'/' + blob[1] blobName = blob[3] blobHash = blob[2] blobTab[blobName] = [None, blobHash, blobURL] # Look for the file modulehash.txt and if it exists, use it to fill # in the local hashes it lists. We do not distribute so it doesn't # show up in the github listing. We want the local hash to reflect # the actual local files, which might have been diddled locally. mhPath = os.path.join(IMC.appBasePath, 'modulehashes.txt') try: mhFile = open(mhPath, 'r') for line in mhFile: [modname, localhash] = line.split() if modname in blobTab: blobTab[modname][0] = localhash except: # presumably the file doesn't exist pass # Run through the blobTab and try to get hash values for any # modules that don't have a local hash yet (because modulehashes # didn't exist -- or didn't list them because they're new to us). for modName in blobTab: if blobTab[modName][0] is None: modPath = os.path.join(IMC.appBasePath, modName) try: modFile = open(modPath, 'r') modText = modFile.read() hasher = initializedSHA1.copy() hasher.update(str(len(modText))) hasher.update(b'\000') hasher.update(modText) blobTab[modName][0] = hasher.hexdigest() except: # presumably modname doesn't exist (new module?) pass # Run through the blobTab and make a new table, updaTab, listing # the members where localhash differs from master hash. updaTab = {} for modName in blobTab: if blobTab[modName][0] != blobTab[modName][1]: updaTab[modName] = blobTab[modName] # If there are no names left in the updaTab, the app is up to date! if len(updaTab) == 0: pqMsgs.infoMsg('PPQT is up to date.') return # There are one or more modules needing updating. Ask the user # if we should proceed. ans = pqMsgs.okCancelMsg( '{0} module(s) can be updated.'.format(len(updaTab)), 'Shall we proceed?') if not ans: pqMsgs.infoMsg('PPQT remains unchanged.') return # User said OK to do it. Read the text of the updated modules from # github and save it in the updaTab. for modName in updaTab: page = slurp(updaTab[modName][2]) if page is None: pqMsgs.warningMsg('Some problem reading update modules', 'PPQT is unchanged.') return updaTab[modName].append(page) # All update texts read correctly. Now open each for writing, # appending the file object to the updaTab entry. for modName in updaTab: try: modPath = os.path.join(IMC.appBasePath, modName) modFile = open(modPath, 'w') updaTab[modName].append(modFile) except Exception: pqMsgs.warningMsg('Updated modules are not writable' 'PPQT is unchanged.') return # All files open for writing and text is ready. Write them. for modName in updaTab: try: modFile = updaTab[modName][4] modFile.write(updaTab[modName][3]) modFile.flush() os.fsync(modFile.fileno()) modFile.close() except Exception as e: # This is the bad case: some amount of writing done but not # all of it complete. PPQT is in an inconsistent state. pqMsgs.warningMsg( 'Error writing updated module(s)!', 'PPQT is in an inconsistent state\nDownload a complete new copy' ) return # All updates complete. Record local hashes in modulehashes.txt try: mhFile = open(mhPath, 'w') for modName in blobTab: mhFile.write(modName + ' ' + blobTab[modName][1] + '\n') mhFile.close() except Exception as e: pass pqMsgs.infoMsg('Updates applied.', 'Changes take effect when PPQT is restarted.') return
def checkForUpdates(): # Step one, read the code display for the master page = slurp('https://github.com/tallforasmurf/PPQT') if page is None: pqMsgs.warningMsg('Unable to contact Github', 'Perhaps try again later?') return # the embedded URLs usable. hit = reGetMasterSHA.search(page) if hit is None: pqMsgs.warningMsg('Github page format not as expected', 'Probable bug, update not available') return masterSHA = hit.group(1) page = re.sub(masterSHA,'master',page) # Step three, make a list of all the "blobs" mentioned, which is just # all the committed modules, pqXXX.py and pqHelp.html. Ignoring the # extras -- the extras folder appears as a "tree" item and we could # follow it and list all the blobs extras/* but we are not. blobs = reBlobLine.findall(page) # blobs is a list of 4-tuples, the (/1, /2, /3, /4) from reBlobLine above # Now make a dict with 3-item values, # { modname:[ None, masterhash, masterURL] } where None will be filled # in with the local hash value shortly. blobTab = {} for blob in blobs: blobURL = u'https://raw.github.com' + blob[0] + u'/' + blob[1] blobName = blob[3] blobHash = blob[2] blobTab[blobName] =[None,blobHash,blobURL] # Look for the file modulehash.txt and if it exists, use it to fill # in the local hashes it lists. We do not distribute so it doesn't # show up in the github listing. We want the local hash to reflect # the actual local files, which might have been diddled locally. mhPath = os.path.join(IMC.appBasePath,'modulehashes.txt') try: mhFile = open(mhPath,'r') for line in mhFile: [modname, localhash] = line.split() if modname in blobTab: blobTab[modname][0] = localhash except: # presumably the file doesn't exist pass # Run through the blobTab and try to get hash values for any # modules that don't have a local hash yet (because modulehashes # didn't exist -- or didn't list them because they're new to us). for modName in blobTab: if blobTab[modName][0] is None: modPath = os.path.join(IMC.appBasePath,modName) try: modFile = open(modPath,'r') modText = modFile.read() hasher = initializedSHA1.copy() hasher.update(str(len(modText))) hasher.update(b'\000') hasher.update(modText) blobTab[modName][0] = hasher.hexdigest() except: # presumably modname doesn't exist (new module?) pass # Run through the blobTab and make a new table, updaTab, listing # the members where localhash differs from master hash. updaTab = {} for modName in blobTab: if blobTab[modName][0] != blobTab[modName][1] : updaTab[modName] = blobTab[modName] # If there are no names left in the updaTab, the app is up to date! if len(updaTab) == 0: pqMsgs.infoMsg('PPQT is up to date.') return # There are one or more modules needing updating. Ask the user # if we should proceed. ans = pqMsgs.okCancelMsg('{0} module(s) can be updated.'.format(len(updaTab)), 'Shall we proceed?') if not ans: pqMsgs.infoMsg('PPQT remains unchanged.') return # User said OK to do it. Read the text of the updated modules from # github and save it in the updaTab. for modName in updaTab: page = slurp(updaTab[modName][2]) if page is None: pqMsgs.warningMsg('Some problem reading update modules', 'PPQT is unchanged.') return updaTab[modName].append(page) # All update texts read correctly. Now open each for writing, # appending the file object to the updaTab entry. for modName in updaTab: try: modPath = os.path.join(IMC.appBasePath,modName) modFile = open(modPath, 'w') updaTab[modName].append(modFile) except Exception: pqMsgs.warningMsg('Updated modules are not writable' 'PPQT is unchanged.') return # All files open for writing and text is ready. Write them. for modName in updaTab: try: modFile = updaTab[modName][4] modFile.write(updaTab[modName][3]) modFile.flush() os.fsync(modFile.fileno()) modFile.close() except Exception as e: # This is the bad case: some amount of writing done but not # all of it complete. PPQT is in an inconsistent state. pqMsgs.warningMsg('Error writing updated module(s)!', 'PPQT is in an inconsistent state\nDownload a complete new copy') return # All updates complete. Record local hashes in modulehashes.txt try: mhFile = open(mhPath,'w') for modName in blobTab: mhFile.write(modName + ' ' + blobTab[modName][1] + '\n') mhFile.close() except Exception as e: pass pqMsgs.infoMsg('Updates applied.', 'Changes take effect when PPQT is restarted.') return
def loadMetadata(self,metaStream): sectionRE = QRegExp( u"\{\{(" + '|'.join ( ['PAGETABLE','CHARCENSUS','WORDCENSUS','BOOKMARKS', 'NOTES','GOODWORDS','BADWORDS','CURSOR','VERSION', 'STALECENSUS','NEEDSPELLCHECK','ENCODING', 'DOCHASH', 'MAINDICT'] ) \ + u")(.*)\}\}", Qt.CaseSensitive) metaVersion = 0 # base version while not metaStream.atEnd() : qline = metaStream.readLine().trimmed() if qline.isEmpty() : continue # allow blank lines between sections if sectionRE.exactMatch(qline) : # section start section = sectionRE.cap(1) argument = unicode(sectionRE.cap(2).trimmed()) endsec = QString(u"{{/" + section + u"}}") if section == u"VERSION": if len(argument) != 0 : metaVersion = int(argument) continue # no more data after {{VERSION x }} elif section == u"STALECENSUS" : if argument == u"TRUE" : IMC.staleCensus = IMC.staleCensusLoaded continue # no more data after {{STALECENSUS x}} elif section == u"NEEDSPELLCHECK" : if argument == u"TRUE" : IMC.needSpellCheck = True continue # no more data after {{NEEDSPELLCHECK x}} elif section == u"ENCODING" : IMC.bookSaveEncoding = QString(argument) continue elif section == u"MAINDICT" : IMC.bookMainDict = QString(argument) continue elif section == u"DOCHASH" : IMC.metaHash = argument continue elif section == u"PAGETABLE": qline = metaStream.readLine() while (not qline.startsWith(endsec)) and (not qline.isEmpty()): IMC.pageTable.metaStringIn(qline) qline = metaStream.readLine() continue elif section == u"CHARCENSUS": qline = metaStream.readLine() while (not qline.startsWith(endsec)) and (not qline.isEmpty()): # can't just .split the char census, the first # char is the char being counted and it can be a space. str = unicode(qline) parts = str[2:].split(' ') IMC.charCensus.append(QString(str[0]),int(parts[0]),int(parts[1])) qline = metaStream.readLine() continue elif section == u"WORDCENSUS": qline = metaStream.readLine() while (not qline.startsWith(endsec)) and (not qline.isEmpty()): parts = unicode(qline).split(' ') IMC.wordCensus.append(QString(parts[0]),int(parts[1]),int(parts[2])) qline = metaStream.readLine() continue elif section == u"BOOKMARKS": qline = metaStream.readLine() while (not qline.startsWith(endsec)) and (not qline.isEmpty()): parts = unicode(qline).split(' ') tc = QTextCursor(self.document() ) tc.setPosition(int(parts[1])) if len(parts) == 3 : # early versions didn't save anchor tc.movePosition(int(parts[2]),QTextCursor.KeepAnchor) self.bookMarkList[int(parts[0])] = tc qline = metaStream.readLine() continue elif section == u"NOTES": e = IMC.notesEditor e.setUndoRedoEnabled(False) qline = metaStream.readLine() while (not qline.startsWith(endsec)) and not metaStream.atEnd(): if qline.startsWith(u"\xfffd"): # escaped {{ qline.remove(0,1) e.appendPlainText(qline) qline = metaStream.readLine() e.setUndoRedoEnabled(True) continue elif section == u"GOODWORDS" : # not going to bother checking for endsec return, # if it isn't that then we will shortly fail anyway w = IMC.goodWordList.load(metaStream,endsec) continue elif section == u"BADWORDS" : w = IMC.badWordList.load(metaStream,endsec) continue elif section == u"CURSOR" : # restore selection as of save p1p2 = argument.split(' ') tc = QTextCursor(self.document()) tc.setPosition(int(p1p2[0]),QTextCursor.MoveAnchor) tc.setPosition(int(p1p2[1]),QTextCursor.KeepAnchor) self.setTextCursor(tc) else: # this can't happen; section is text captured by the RE # and we have accounted for all possibilities raise AssertionError, "impossible metadata" else: # Non-blank line that doesn't match sectionRE? pqMsgs.infoMsg( "Unexpected line in metadata: {0}".format(pqMsgs.trunc(qline,20)), "Metadata may be incomplete, suggest quit") break
def loadMetadata(self, metaStream): sectionRE = QRegExp( u"\{\{(" + '|'.join ( ['PAGETABLE','CHARCENSUS','WORDCENSUS','BOOKMARKS', 'NOTES','GOODWORDS','BADWORDS','CURSOR','VERSION', 'STALECENSUS','NEEDSPELLCHECK','ENCODING', 'DOCHASH', 'MAINDICT'] ) \ + u")(.*)\}\}", Qt.CaseSensitive) metaVersion = 0 # base version while not metaStream.atEnd(): qline = metaStream.readLine().trimmed() if qline.isEmpty(): continue # allow blank lines between sections if sectionRE.exactMatch(qline): # section start section = sectionRE.cap(1) argument = unicode(sectionRE.cap(2).trimmed()) endsec = QString(u"{{/" + section + u"}}") if section == u"VERSION": if len(argument) != 0: metaVersion = int(argument) continue # no more data after {{VERSION x }} elif section == u"STALECENSUS": if argument == u"TRUE": IMC.staleCensus = IMC.staleCensusLoaded continue # no more data after {{STALECENSUS x}} elif section == u"NEEDSPELLCHECK": if argument == u"TRUE": IMC.needSpellCheck = True continue # no more data after {{NEEDSPELLCHECK x}} elif section == u"ENCODING": IMC.bookSaveEncoding = QString(argument) continue elif section == u"MAINDICT": IMC.bookMainDict = QString(argument) continue elif section == u"DOCHASH": IMC.metaHash = argument continue elif section == u"PAGETABLE": qline = metaStream.readLine() while (not qline.startsWith(endsec)) and ( not qline.isEmpty()): IMC.pageTable.metaStringIn(qline) qline = metaStream.readLine() continue elif section == u"CHARCENSUS": qline = metaStream.readLine() while (not qline.startsWith(endsec)) and ( not qline.isEmpty()): # can't just .split the char census, the first # char is the char being counted and it can be a space. str = unicode(qline) parts = str[2:].split(' ') IMC.charCensus.append(QString(str[0]), int(parts[0]), int(parts[1])) qline = metaStream.readLine() continue elif section == u"WORDCENSUS": qline = metaStream.readLine() while (not qline.startsWith(endsec)) and ( not qline.isEmpty()): parts = unicode(qline).split(' ') IMC.wordCensus.append(QString(parts[0]), int(parts[1]), int(parts[2])) qline = metaStream.readLine() continue elif section == u"BOOKMARKS": qline = metaStream.readLine() while (not qline.startsWith(endsec)) and ( not qline.isEmpty()): parts = unicode(qline).split(' ') tc = QTextCursor(self.document()) tc.setPosition(int(parts[1])) if len(parts ) == 3: # early versions didn't save anchor tc.movePosition(int(parts[2]), QTextCursor.KeepAnchor) self.bookMarkList[int(parts[0])] = tc qline = metaStream.readLine() continue elif section == u"NOTES": e = IMC.notesEditor e.setUndoRedoEnabled(False) qline = metaStream.readLine() while (not qline.startsWith(endsec) ) and not metaStream.atEnd(): if qline.startsWith(u"\xfffd"): # escaped {{ qline.remove(0, 1) e.appendPlainText(qline) qline = metaStream.readLine() e.setUndoRedoEnabled(True) continue elif section == u"GOODWORDS": # not going to bother checking for endsec return, # if it isn't that then we will shortly fail anyway w = IMC.goodWordList.load(metaStream, endsec) continue elif section == u"BADWORDS": w = IMC.badWordList.load(metaStream, endsec) continue elif section == u"CURSOR": # restore selection as of save p1p2 = argument.split(' ') tc = QTextCursor(self.document()) tc.setPosition(int(p1p2[0]), QTextCursor.MoveAnchor) tc.setPosition(int(p1p2[1]), QTextCursor.KeepAnchor) self.setTextCursor(tc) else: # this can't happen; section is text captured by the RE # and we have accounted for all possibilities raise AssertionError, "impossible metadata" else: # Non-blank line that doesn't match sectionRE? pqMsgs.infoMsg( "Unexpected line in metadata: {0}".format( pqMsgs.trunc(qline, 20)), "Metadata may be incomplete, suggest quit") break