Python AttributeError / NameError with confirmed imports - python-3.x

I have two files, InvertedIndex.py and gui.py for an Inverted Index program I'm working on.
Both files work correctly on their own and have the correct imports. When I run python InvertedIndex.py things function properly and return the values to the interface, but when I run python gui.py, enter my search term and click search I am met with this:
C:\Users\MTXIII\Documents\Dev\Python\Projects\InvIndex\gui\InvInd\Test>python gui.py
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\MTXIII\Anaconda3\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\Users\MTXIII\Documents\Dev\Python\Projects\InvIndex\gui\InvInd\Test\gui.py", line 17, in open
for line in bck.index_lookup_query(Term.get()):
AttributeError: module 'InvertedIndex' has no attribute 'index_lookup_query'
Furthermore, when I run these checks I get NameError: name 'bck' is not defined (bck is the alias given in file for InvertedIndex.py)
>>> import gui
>>> print(bck)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bck' is not defined
>>> print(dir(bck))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bck' is not defined
>>> for line in bck.index_lookup_query(Term.get()):
...
I have also confirmed that index_lookup_query is within the namespace of InvertedIndex.
>>> import InvertedIndex >>> print(dir(InvertedIndex)) ['Appearance', 'Database', 'InvertedIndex', 'builtins', 'cached', 'doc', 'file', 'loader', 'name', 'package', 'spec', 'g', 'index_documents', 'index_lookup_query', 'main', 're'] >>>
My Code is below:
gui.py:
```
from tkinter import *
import InvertedIndex as bck
# from InvertedIndex import index_lookup_query
LARGE_FONT = ("Verdana", 12)
NORM_FONT = ("Verdana", 10)
SMALL_FONT = ("Verdana", 8)
def open():
top = Toplevel()
searching = 'Occurences of the term: ' + Term.get()
lbl = Label(top, text=searching, width = 60, font = LARGE_FONT).pack()
listbox = Listbox(top)
listbox.pack()
# for line in bck.index_lookup_query(Term.get()):
for line in bck.index_lookup_query(Term.get()):
listbox.insert(END, line)
#create the tkinter window.
root = Tk()
root.geometry('300x85')
# frame = Frame(root, width=100, height=15, bg='white')
# frame.pack()
# to rename the title of the root
root.title("Term Search")
#Label for entry box.
# Label(root, text = "Enter the term you would like to search for:").grid(row = 0)
# Entry box.
Term = Entry(root, width=30)
Term.pack(side = TOP)
Term.insert(0,"Enter the term to search for:")
# Term.grid(row = 0, column = 0)
# Search button.
search_for = "Searching for " + Term.get()
b1 = Button(root, text = "Search!", bg = 'grey', fg = "red", width = 30, command = open)
b1.pack()
# b1.grid(row = 1, column = 0) #'fg or foreground' is for coloring the contents (buttons)
mainloop()
```
InvertedIndex.py:
```
import re
import gui as g
class Appearance:
"""
Represents the appearance of a term in a given document, along with the
frequency of appearances in the same one.
"""
def __init__(self, docId, frequency):
self.docId = docId
self.frequency = frequency
def __repr__(self):
"""
String representation of the Appearance object
"""
return str(self.__dict__)
class Database:
"""
In memory database representing the already indexed documents.
"""
def __init__(self):
self.db = dict()
def __repr__(self):
"""
String representation of the Database object
"""
return str(self.__dict__)
def get(self, id):
return self.db.get(id, None)
def add(self, document):
"""
Adds a document to the DB.
"""
return self.db.update({document['id']: document})
def remove(self, document):
"""
Removes document from DB.
"""
return self.db.pop(document['id'], None)
class InvertedIndex:
"""
Inverted Index class.
"""
def __init__(self, db):
self.index = dict()
self.db = db
def __repr__(self):
"""
String representation of the Database object
"""
return str(self.index)
def index_document(self, document):
"""
Process a given document, save it to the DB and update the index.
"""
# Remove punctuation from the text.
clean_text = re.sub(r'[^\w\s]','', document['text'])
terms = clean_text.split(' ')
appearances_dict = dict()
# Dictionary with each term and the frequency it appears in the text.
for term in terms:
term_frequency = appearances_dict[term].frequency if term in appearances_dict else 0
appearances_dict[term] = Appearance(document['id'], term_frequency + 1)
# Update the inverted index
update_dict = { key: [appearance]
if key not in self.index
else self.index[key] + [appearance]
for (key, appearance) in appearances_dict.items() }
self.index.update(update_dict)
# Add the document into the database
self.db.add(document)
return document
def lookup_query(self, query):
"""
Returns the dictionary of terms with their correspondent Appearances.
This is a very naive search since it will just split the terms and show
the documents where they appear.
"""
return { term: self.index[term] for term in query.split(' ') if term in self.index }
def index_documents(index):
document1 = {
'id': '1',
'text': 'It resides in a cavern on the moon.'
}
document2 = {
'id': '2',
'text': 'The lunar brew expedition.'
}
document3 = {
'id': '3',
'text': 'beer beer beer!'
}
document4 = {
'id': '4',
'text': 'Space travel has changed to way we consume beer.'
}
document5 = {
'id': '5',
'text': 'Over the moon brew.'
}
document6 = {
'id': '6',
'text': 'Deep in the caverns of the moon, beer.'
}
index.index_document(document1)
index.index_document(document2)
index.index_document(document3)
index.index_document(document4)
index.index_document(document5)
index.index_document(document6)
def index_lookup_query(search_term):
db = Database()
index = InvertedIndex(db)
index_documents(index)
result = index.lookup_query(search_term)
for key, value in result.items():
for appearance in value:
yield '{}, {}'.format(appearance.docId, appearance.frequency)
def main():
search_term = input('Enter term to search for: ')
#
# result = index.lookup_query(search_term)
for line in index_lookup_query(search_term):
print(line)
print("-----------------------------")
if __name__ == "__main__":
main()
```

You have a case of circular dependency.
module1.py
import module2
module2.func()
module2.py
import module1
def func():
print("hello")
Now if you run
python module1.py
You will run into module 'module2' has no attribute 'func' error.
The reason this happens is that the line module2.func() isn't executed when you think it will be executed. Here is how the program flows:
import module2 at line1, module1 (program now goes to module2)
import mudule1 at line1, module2 (program now goes to module1 again)
import module2 at line1, module1 (program doesn't go to module2 again because module2 has been imported before.)
module2.func() at line2, module1. (throws an error because we have never reached to the func definition at line2, module2. So, module2 doesn't yet have func
The easiest way to solve this problem is to get rid of the circular import. In your case, remove import gui as g from the InvertedIndex.py since it seems unnecessary.

Related

What can i do to print information from a nested dictionary that is send to class, and i need to show the result on the GUI

I am very stuck by trying to use tkinter, right now I am trying to print a receipt, my code works without the GUI, it prints the receipt sending the necessary information to a class, but now the professor wants us to have a GUI.
This is a one of the classes that I am using:
class Combo:
def __init__(self, dish, drink, order, price):
self.dish = dish
self.drink = drink
self.order = order
self.price = price
def combo_receipt(self, combo_number):
"""
This is for printing on the receipt the information of the combo
:return:
"""
return f"Combo {combo_number}.\nDish {self.dish}.\nDrink Order {self.drink}.\nFood Order {self.order}.\n" \
f"Price {self.price}.\n -------------"
This is how I am recollecting the information from a nested dictionary to send it to another function:
def receipt_print(customer_receipts, taxes):
"""
This function will start the process of printing the receipt of the customer
:param customer_receipts: receipts dictionary
:param taxes: the tax to the math operation
:return:
"""
for key, value in customer_receipts.items():
print(key)
customer_name = input("Which receipt do you want to print?")
if customer_name in customer_receipts:
loop_print = int(customer_receipts[customer_name]["n_orders"])
num_of_orders = 0
total = 0
for n in range(loop_print):
if f"id{num_of_orders}" in customer_receipts[customer_name]:
if "fries" in customer_receipts[customer_name][f"id{num_of_orders}"]:
fr = "fries"
order_type = "food"
id_num_of_orders = f"id{num_of_orders}"
cost = int(customer_receipts[customer_name][f"id{num_of_orders}"]["fries"]["price"])
total += cost
order_print(fr, customer_receipts, order_type, customer_name, id_num_of_orders)
num_of_orders += 1
elif "soda" in customer_receipts[customer_name][f"id{num_of_orders}"]:
sd = "soda"
order_type = "drink"
id_num_of_orders = f"id{num_of_orders}"
cost = int(customer_receipts[customer_name][f"id{num_of_orders}"][sd]["price"])
total += cost
order_print(sd, customer_receipts, order_type, customer_name, id_num_of_orders)
num_of_orders += 1
elif "combo_1" in customer_receipts[customer_name][f"id{num_of_orders}"]:
cb1 = "combo_1"
combo_num = "1"
id_num_of_orders = f"id{num_of_orders}"
cost = int(customer_receipts[customer_name][f"id{num_of_orders}"][cb1]["price"])
total += cost
combo_print(cb1, customer_receipts, combo_num, customer_name, id_num_of_orders)
num_of_orders += 1
elif "combo_2" in customer_receipts[customer_name][f"id{num_of_orders}"]:
cb2 = "combo_2"
combo_num = "2"
id_num_of_orders = f"id{num_of_orders}"
cost = int(customer_receipts[customer_name][f"id{num_of_orders}"][cb2]["price"])
total += cost
combo_print(cb2, customer_receipts, combo_num, customer_name, id_num_of_orders)
num_of_orders += 1
elif "pizza" in customer_receipts[customer_name][f"id{num_of_orders}"]:
pz = "pizza"
id_num_of_orders = f"id{num_of_orders}"
cost = int(customer_receipts[customer_name][f"id{num_of_orders}"][pz]["price"])
total += cost
dish_print(pz, customer_receipts, customer_name, id_num_of_orders)
num_of_orders += 1
else:
sp = "spaghetti"
id_num_of_orders = f"id{num_of_orders}"
cost = int(customer_receipts[customer_name][f"id{num_of_orders}"][sp]["price"])
total += cost
dish_print(sp, customer_receipts, customer_name, id_num_of_orders)
num_of_orders += 1
total_print(total, taxes)
else:
print("Wrong receipt.\nBack to the menu")
In this case, the function that will handle the combos that the customer order, is:
def combo_print(combo, customer_receipts, comb_num, customer_name, id_or):
"""
When this function is call, it will print the combo information
:param combo: a variable to know which combo is in the order
:param customer_receipts: receipts dictionary
:param comb_num: a variable to be sent to the class Order
:param customer_name: a variable with the name of the customer to read the receipt dictionary
:param id_or: a variable with the name of the customer to read the receipt dictionary
:return:
"""
combo_order = customer_receipts[customer_name][id_or][combo]["order"]
combo_price = customer_receipts[customer_name][id_or][combo]["price"]
combo_drink = customer_receipts[customer_name][id_or][combo]["drink"]
combo_dish = customer_receipts[customer_name][id_or][combo]["dish"]
fill_object = Combo(combo_dish, combo_drink,combo_order, combo_price)
print(fill_object.combo_receipt(comb_num))
And this will be calling the function def combo_receipt on the class class Combo:, so with this class and another three, one for Dishes, other one for Orders and the last one for the total, it will be printing the receipt for the customer.
This is what it prints:
Just for visualize, the nested directory looks like this:
receipts = {"jONH": {"n_orders": 1,
"id0": {"combo_2": {"dish": "Spaghetti Carbonara",
"drink": "Soda",
"order": "French Fries",
"price": "10", "id": "combo"}}},
"Josh": {"n_orders": 2,
"id0": {"combo_1": {"dish": "Personal Pizza",
"drink": "Soda",
"order": "French Fries",
"price": "8",
"id": "combo"}},
"id1": {"soda": {"order": "Soda",
"price": "2",
"id": "order"}
}
}
}
But as I already said, I need to use a GUI, but I know if there is a way to save the return value from the function def combo_receipt on the class class Combo: and send it to the GUI or what I can do to still be using the class and the GUI, cause it is requested.
I can't show you anything about my tries with this, cause I am really stuck with the GUI, so I am just watching video guides of tkinter or looking in google for information.
I will appreciate any advice, link or anything that help me to understand what I need to do
I have here an oop solution for the GUI where you can implement your functions. In the main file you create the app, mainFrame and Notebook with a tab.
In the second File you get the class with the init function for Entries/Labels/Buttons, you have to add elements you need. On the bottom you are able to implement your functions. Hope that helps you further with the GUI.
main.py:
import tkinter as tk
from tkinter import ttk
from abc import createUI0
# class MainFrame that inherits from ttk.Frame
class MainFrame(ttk.Frame): #ttk.Frame
def __init__(self, container): #init method
super().__init__(container)
# Create notebook
self.tabControl = ttk.Notebook(self)
tab1 = createUI0(self.tabControl)
# Create Tab from tab1 from file XYZ
self.tabControl.add(tab1, text ='XYZ')
self.tabControl.pack(expand = 1, fill ="both")
if __name__ == "__main__":
app = tk.Tk()
app.title('XZY')
app.geometry('670x580')
app.resizable(0, 0)
MainFrame(app).pack(side="top", fill="both", expand=True)
app.mainloop()
abc.py:
import tkinter as tk
from tkinter import ttk
from tkinter import *
class createUI0(ttk.Frame):
def __init__(self, container): #init method
super().__init__(container)
# field options
options = {'padx': 5, 'pady': 5}
# Titel Labels
self.title = ttk.Label(self, text='XXX', font=('Helvetica', 17, 'bold'))
self.title.grid(column=1, row=0, sticky=tk.W, **options)
# Item Detail Labels
self.itemDetail = ttk.Label(self, text='YYY:', font=('Helvetica', 16, 'bold'))
self.itemDetail.grid(column=0, row=5, sticky=tk.W, **options)
# XEntry, your variable to work with
self.X = tk.StringVar()
self.XEntry = ttk.Entry(self, width=23, textvariable=self.X)
self.XEntry.grid(column=1, row=11, sticky=tk.W, **options)
self.XEntry.focus()
# Button to start your function for example
self.button_create = ttk.Button(self, width = 15, text='use YourFunction', command=self.yourFunction)
self.button_create.grid(column=0, row=22, **options, sticky=tk.W)
def yourFunction(self):
#your function
pass

Name error in class when importing my script file to another from

I wrote some code in a script file script.py
from functools import reduce
class Operators:
def __init__(self, names):
self.op_name = []
for name in names:
self.op_name.append(name)
def __matmul__(self, other):
if type(other) is Operators:
new_op_list = self.op_name + other.op_name
return Operators(new_op_list)
def __str__(self):
return ' # '.join(map(str, self.op_name))
class Single_Ket:
def __init__(self, label: tuple, coeff, operator = []):
self.label = label
self.coeff = coeff
self.operators = operator
def __str__(self):
Operator_Str = str( eval(' # '.join(map(str, self.operators))) )
if type(self.label) is tuple:
return '{} * {} # | {} >'.format(self.coeff, Operator_Str, ', '.join(map(str, self.label)))
else:
return f'{self.coeff} * {Operator_Str}.|{self.label}>'
if __name__ == '__main__':
Jp = Operators(['Jp'])
Jm = Operators(['Jm'])
ket_1 = Single_Ket((1, 1), 1, [Jp # Jm])
print(ket_1)
which works fine when I run it.
However, when I import test.py into another file test.py and run
from script import*
Jp = Operators(['Jp'])
Jm = Operators(['Jm'])
ket_1 = Single_Ket((1, 1), 1, [Jp # Jm])
print(ket_1)
I got the error message 'NameError: name 'Jp' is not defined'. Given I defined Jp in test.py, I don't understand the reason why I get name error.
What is the way to fix this, or is there any related article I can look at to fix this?

I'm having problems reading a csv file and inserting the words into a text box in pyqt. The words are not printing into the textbox like they should

This is the modules that are needed.
import sys
import csv
from csv import *
from PyQt4 import QtCore, QtGui, uic
qtCreatorFile = "Inquiry.ui" # Enter file here.
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
Hebrew = {'a':1,'b':2,'c':3,'d':4,'e':5,'f':6,'g':7,'h':8,'i':9,\
'j':600,'k':10,'l':20,'m':30,'n':40,'o':50,'p':60,'q':70,'r':80,\
's':90,'t':100,'u':200,'v':700,'w':900,'x':300,'y':400,'z':500}
Some other code that is important to help reproduce the problem:
Create the GUI:
def __init__(self):
"Create UI"
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
self.btnCalculate.clicked.connect(self.Calculate)
def Calculate(self):
The Event:
try:
Event = str(self.txtInquiry)
except TypeError:
pass
The Word Text File Path:
y = 'C:/Users/Jacob-C/Documents/words_alpha.txt'
These are the functions used.
Calculates the value of each word from the key mappings in the gematria system used.
def gematric_value(x, L):
value = 0
for v in x.lower():
try:
value = value + L[v]
except KeyError:
pass
return value
Modulo Function used heavily in integer reduction.
def MOD_CALC(x, y):
return (x % y)
This function takes a number and integer reduces it.
def Check_Value(x):
if x > 9 and MOD_CALC(x, 9) == 0:
return (MOD_CALC(x, 9) + 9)
elif x > 9 and MOD_CALC(x, 9) != 0:
return MOD_CALC(x, 9)
else:
return x
This is the function that does not insert the words into the plain textbox.
def Gematria(f, Hebrew, EN):
opens text file and converts it to a csv file. Then reads each word in the text file and compares the gematric value of the word and the gematric value of the event. If they match, the word is inserted to the plain text box on the qt form. This function does not do what is intended. Instead it doesn't insert anything into the plain text box.
with open(f, 'r', newline='') as input_file_name:
input_file = csv.reader(input_file_name, delimiter=' ', quotechar='|')
for word in input_file:
GV = Check_Value(gematric_value(word, L))
if GV == EN:
self.txtWords.insertPlainText(", ".join(word))
Integer reduces the Event Number
HN = gematric_value(Event, Hebrew) # Hebrew Event Number
MOD_HN = Check_Value(HN) # Reduced Hebrew Event Number
The Call:
Gematria(y, Hebrew, MOD_HN)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
Traceback (most recent call last):
File "C:\Users\Jacob-C\Documents\Numerology_Predict.py", line 146, in <module>
Launch_Program()
File "C:\Users\Jacob-C\Documents\Numerology_Predict.py", line 144, in Launch_Program
Gematria(y, L, EN)
File "C:\Users\Jacob-C\Documents\Numerology_Predict.py", line 116, in Gematria
GV = Check_Value(Event_Number(word, L))
File "C:\Users\Jacob-C\Documents\Numerology_Predict.py", line 95, in Event_Number
for e in E.lower():
AttributeError: 'list' object has no attribute 'lower'
My Answer:
def Gematria(f, L, EN):
with open(f, 'r') as input_file:
for word in input_file:
GV = Check_Value(Event_Number(word, L))
if GV == EN:
print(word)

TypeError: 'str' object does not support item assignment google api

So I'd like to make an app, that upload a file to google drive, the app create the textfile by typing Variables.
So the app works, but if I try to link it with Google Drive, it just won't upload. I'm new to Python (started like week ago), so I would like a positive response.
Full console log:
Authentication successful.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Akush\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:/Users/Akush/PycharmProjects/untitled/importer.py", line 15, in importfilestogoogle
file1.Upload(c+'.txt') # Upload the file.
File "C:\Users\Akush\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pydrive\files.py", line 285, in Upload
self._FilesInsert(param=param)
File "C:\Users\Akush\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pydrive\auth.py", line 75, in _decorated
return decoratee(self, *args, **kwargs)
File "C:\Users\Akush\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pydrive\files.py", line 364, in _FilesInsert
param['body'] = self.GetChanges()
TypeError: 'str' object does not support item assignment
The code which generated the error:
import tkinter as tk
import sys
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
import random
def importfilestogoogle():
gauth = GoogleAuth()
gauth.LocalWebserverAuth()
drive = GoogleDrive(gauth)
file1 = drive.CreateFile({"mimeType": "text/csv", "parents": [{"kind":
"drive#fileLink", "id": random.randrange(1,None)}]})
file1.SetContentFile(c+'.txt')
file1.Upload(c+'.txt') # Upload the file.
def press2(event):
global c
c = file_entry.get()
file_entry.delete(0,'end')
screen2.destroy()
def getnamefile():
global c
c = file_entry.get()
file_entry.delete(0,'end')
screen2.destroy()
def NameFilescren():
global screen2
global file_entry
screen2 = tk.Toplevel(root1)
screen2.title('Nazwa Pliku')
screen2.geometry('240x80')
screen_label = tk.Label(screen2,text='Wprowadź nazwe:')
screen_label.pack()
file_entry = tk.Entry(screen2)
file_entry.pack()
file_button = tk.Button(screen2, text='Kliknij
tutaj',command=getnamefile)
file_button.pack()
screen2_label = tk.Label(screen2, text='Plik tekstowy zapisuje się w
folderze aplikacji')
screen2_label.pack()
submit2 = tk.Button(root1, command=press2)
screen2.bind('<Return>', press2)
def quit(event):
sys.exit()
# po naciśnięciu przycisku(button) wykonuje daną czynność
def click():
a = e.get()
e.delete(0, 'end')
f = open(c +'.txt', 'a')
f.write("\n")
f.write(a)
f.close()
# po naciśnięciu klawisza na klawiaturze wykonuje dana czynność
def press(event):
a = e.get()
e.delete(0, 'end')
f = open(c + '.txt', 'a')
f.write('\n')
f.write(a)
f.close()
def window2():
global e
global root1
global label
global label2
root1 = tk.Tk()
label = tk.Label(root1, text='Wprowadź dane :')
label.place(x=50, y=10)
e = tk.Entry(root1)
e.place(x=175, y=10)
button = tk.Button(root1, text='------>', command=click)
button.place(x=145, y=50)
submit = tk.Button(root1, command=press)
exit = tk.Button(root1, command=quit)
root1.bind('<Return>', press)
root1.bind('<Escape>', quit)
button2 = tk.Button(root1, text='Wybierz nazwe Pliku',
command=NameFilescren)
button2.place(x=5,y=315)
button3 = tk.Button(root1, text='Upload''uj do Google Drive',
command=importfilestogoogle)
button3.place(x=200, y=315)
root1.title('Przechowywacz danych')
root1.geometry('350x350')
root1.mainloop()
window2()

Tkinter Text widget maximum recursion depth using idlelib Delegator/Percolator

After testing I have concluded that the error
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
text.mainloop()
File "C:\Program Files\Python32\lib\tkinter\__init__.py", line 1009, \
in mainloop
self.tk.mainloop(n)
RuntimeError: maximum recursion depth exceeded
occurs only after there is a character before the INSERT position and the user types a Backspace. Here is my code:
# Import
import tkinter
import tkinter.scrolledtext
import idlelib.Delegator
import idlelib.WidgetRedirector
import idlelib.Percolator
import idlelib.ColorDelegator
import time
import re
# Class
class Highlighter(idlelib.Delegator.Delegator):
def __init__(self):
idlelib.Delegator.Delegator.__init__(self)
self._syntaxes = {}
self._compiled = ""
def setdelegate(self, delegate):
idlelib.Delegator.Delegator.setdelegate(self, delegate)
if delegate is not None:
self.setup()
def insert(self, index, chars, *args):
index = self.index(index)
self.delegate.insert(index, chars, *args)
self.update(index, index + "+%dc" % len(chars))
def delete(self, index1, index2=None):
index = self.index(index1)
self.delete(index1, index2)
self.update(index)
def update(self, index1, index2=None):
self.tag_add("TODO", index1, index2)
self.after(1, self.syntax_highlight)
def setup(self):
background = self.cget("background")
self.tag_configure("TODO", foreground=background, background=None)
def syntax_configure(self, tag, syntax):
"""Configure syntax TAG with pattern SYNTAX."""
self._syntaxes[tag] = syntax
syntax_config = syntax_configure
def syntax_cget(self, tag):
"""Return the pattern of TAG."""
return self._syntaxes[tag]
def syntax_delete(self, tag):
"""Delete syntax TAG from the highlighter."""
self._syntaxes.pop(tag)
def syntax_clear(self):
"""Clear all syntaxes."""
self._syntaxes.clear()
def syntax_compile(self):
"""Compile all syntaxes."""
return "|".join("(?P<%s>%s)" % (tag, pattern)
for tag, pattern in self._syntaxes.items())
def syntax_highlight(self, start="1.0", end="end"):
start = self.index(start)
end = self.index(end)
pattern = self.syntax_compile()
if pattern:
for match in re.finditer(pattern, self.get(start, end)):
tag, sequence = list(match.groupdict().items())[0]
start, stop = match.span()
self.tag_remove("TODO", "1.0", "1.0+%dc" % match.span()[1])
self.tag_add(tag, "1.0+%dc" % start, "1.0+%dc" % stop)
self.tag_delete("TODO")
text = tkinter.Text()
text.pack()
p = idlelib.Percolator.Percolator(text)
h = Highlighter()
p.insertfilter(h)
text.mainloop()
If anyone could explain what the cause/source of the recursion is, it would be much appreciated. Thanks!
The issue was that instead of self.delete(index1, index2) in delete it should have been self.delegate.delete(index1, index2).

Resources