Open XML file in Python and add user input - python

I am creating a program with python 2.7, using Tkinter as the GUI, and elementtree, where the data entered by the user is stored in an XML file. I have managed to create the XML file using python and this saves to the file 'crimeFile.xml', with all empty tags. The GUI also displays the fields and text boxes that allow the user to enter in text. The problem is that when I try and save an entry, I get an error, and the data is not saved to the XML file.
from xml.etree import ElementTree
from xml.etree.ElementTree import Element
from xml.etree.ElementTree import SubElement
import xml.etree.ElementTree as ET
from Tkinter import *
class Application(Frame):
def create_XML(self):
crimeReport = Element('crime report')
caseNo = SubElement(crimeReport, 'case number')
victimDetails = SubElement(caseNo, 'victim details')
victimFirstName = SubElement(victimDetails, 'victims first name')
victimSecondName = SubElement(victimDetails, 'victim surname')
victimAddress = SubElement(victimDetails, 'victim address')
output_file = open('crimeFile.xml', 'w')
output_file.write('<?xml version="1.0"?>')
output_file.write(ElementTree.tostring(crimeReport))
output_file.close()
def save_XML(self):
record = ET.SubElement(self.crimeReport, 'crime report')
caseNoNode = ET.SubElement(record, 'case number')
caseNoNode.text = self.caseNo.get()
victimFirstNameNode = ET.SubElement(record, 'first name')
victimFirstNameNode.text = self.victimFirstName.get()
victimSecondNameNode = ET.SubElement(record, 'surname')
victimSecondNameNode.text = self.victimSecondName.get()
victimAddressNode = ET.SubElement(record, 'address')
victimAddressNode.text = self.victimAddress.get()
self.tree.write('crimeReport.xml')
self.clear_field()
def create_Widgets(self):
self.save = Button(self)
self.save["text"] = "Save",
self.save["command"] = self.save_XML
self.save["bg"] = "cyan"
self.save.grid(row=0,column =2,sticky=W+E+N+S)
self.crimeReportLabel = Label(self, text = 'Crime Report')
self.crimeReportLabel.grid(row=1,column =1,sticky=W)
self.caseNoLabel = Label(self,text="Case Number")
self.caseNoLabel.grid(row=2,column =1,sticky=W)
self.caseNo = Entry(self)
self.caseNo.grid(row=2,column =2,sticky=W)
self.victimDetailsLabel = Label(self,text="Victim Details")
self.victimDetailsLabel.grid(row=3,column =1,sticky=W)
self.victimFirstNameLabel = Label(self,text="First Name")
self.victimFirstNameLabel.grid(row=4,column =1,sticky=W)
self.victimFirstName = Entry(self)
self.victimFirstName.grid(row=4,column =2,sticky=W)
self.victimSecondNameLabel = Label(self,text="Surname")
self.victimSecondNameLabel.grid(row=4,column =3,sticky=W)
self.victimSecondName = Entry(self)
self.victimSecondName.grid(row=4,column =4,sticky=W)
self.victimAddressLabel = Label(self,text="Address")
self.victimAddressLabel.grid(row=6,column =1,sticky=W)
self.victimAddress = Entry(self)
self.victimAddress.grid(row=6,column =2,sticky=W)
def __init__(self, master = None):
Frame.__init__(self, master)
self.grid(column=5,row=25)
self.create_Widgets()
self.create_XML()
crimeReport = Tk()
app = Application(master = crimeReport)
app.mainloop()
crimeReport.destroy()
The error that I get is:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1532, in __call__
return self.func(*args)
File "C:\Users\Laleh\workspace\AdvDB20-02\program1\program1.py", line 60, in save_XML
record = ET.SubElement(self.crimeReport, 'crime report')
AttributeError: Application instance has no attribute 'crimeReport'
What the program is meant to do is create an XML file to use, for multiple entries by the user. Update and store the new entries in this XML file (not overriding the previous ones), so that later it can be searched and a report produced.
I'm a newbie to python and am not sure where I am going wrong?

Your application instance doesn't have any attribute named crimeReport
def save_XML(self):
record = ET.SubElement(self.crimeReport, 'crime report')
^
crimeReport is only defined in your create_XML method. You can define crimeReport as class attribute instead.
class Application(Frame):
crimeReport = Element('crime report')
and use self.crimeReport in your methods

Related

_tkinter.TclError: wrong # args: should be ".!entry4 insert index text"

I'm trying to list all the data i got from my database using tkinter.
I'm following this post: https://www.geeksforgeeks.org/create-table-using-tkinter/
I got this erorr:
File "/Users/nobu/WorkSpace/Python/CommandLineApps/guineapig/guineapig/gui_tkinter.py", line 18, in __init__
self.entry.insert(END, result[i][j])
File "/usr/local/Cellar/python#3.9/3.9.7/Frameworks/Python.framework/Versions/3.9/lib/python3.9/tkinter/__init__.py", line 3056, in insert
self.tk.call(self._w, 'insert', index, string)
_tkinter.TclError: wrong # args: should be ".!entry4 insert index text"
Here's my code:
from tkinter import *
import mysql.connector
import utils
class Table:
def __init__(self,root, result):
# code for creating table
total_rows = len(result)
total_columns = len(result[0])
for i in range(total_rows):
for j in range(total_columns):
self.e = Entry(root, width=20, fg='white')
self.e.grid(row=i, column=j)
self.e.insert(END, result[i][j]) # <- Here I got an error
def get_all():
connection, cursor = utils.connect_db()
with connection:
root = Tk()
cursor.execute("SELECT * FROM item ORDER BY item_id DESC")
result = cursor.fetchall()
if len(result) == 0:
label = Label(text="There are no items. Please create one.")
else:
table = Table(root, result)
root.mainloop()
I'm very new to tkinter. Please help me solve this issue.
Thank you #Bryan Oakley!
My list has None, so I did this:
if result[i][j] is not None:
self.entry.insert(END, result[i][j])
else:
self.entry.insert(END, "None")

Pprint within tkinter

I'm trying to find a way to show a list of titles, urls, and time stamps for a google search/RSS FEED that I'm working on for a GUI. I'm having a lot of trouble trying to find a way to sort the results in a nice readable form. Any articles or guidance as far as what to do would be greatly appreciated!
from tkinter import *
import urllib.request
import feedparser
from pprint import pprint
search_term = ('') #search term for url
quoted_search_term = urllib.parse.quote(search_term)
def go():
text.delete(1.0, END) #delete text
rss_string = 'https://news.google.com/news/section?output=rss'.format (quoted_search_term)
parsed_rss_string = feedparser.parse(rss_string) #assigning variable for parsed feed
text.insert(1.0, parsed_rss_string) #insert text of parsed feed
browser_window = Tk() #tk window
browser_window.title('RSS Feed') #Window title
label = Label(browser_window, text= 'Search:')
entry = Entry(browser_window)
button = Button(browser_window, text='Go', command = go)#Go Button
text = Text(browser_window) #results box
label.pack(side=TOP) #Positioning of search title
entry.pack(side=TOP) #Positioning of search box
button.pack(side=TOP)#Positioning of go
text.pack(side= RIGHT) #Positioning of text
browser_window.mainloop()
To prettified string, use pprint.pformat:
from pprint import pformat
...
def go():
...
parsed = feedparser.parse(rss_string)
prettified = pformat(parsed)
text.insert("1.0", prettified)
NOTE:
there's no placeholder in the url https://news.google.com/news/section?output=rss; no effect of str.format.
feedparser.parse does not return a string, but a dictionary.
UPDATE to show publish date, title, url only, you need to get those entries from dictionaries:
def go():
rss_string = 'https://news.google.com/news/section?output=rss'
parsed = feedparser.parse(rss_string)
text.delete("1.0", END)
for entry in parsed['entries']:
text.insert(END, '{0[published]} - {0[title]} {0[link]}\n\n'.format(entry))

manipulating entry box data

I am trying to make a quiz game. However when I try to make an entry box and manipulate the data it throws an error. What I need is an explanation to how i can properly structure an entry widget and be able to store the inputted data to a variable. Here is the code:
while True:
random_question = random.randint(0, 39)
if questions_asked == 20:
end_label = tkinter.Label(self, "Your score for that round was {} . For another look at your scores go to the scores page".format(score))
end_label.pack()
break
question_label = tkinter.Label(self , text="{}".format(questions[random_question]))
user_entry = tkinter.Entry(self, "Type your answer here : ")
user_entry.pack()
stored_entry = user_entry.get()
remove_key(random_question)
if stored_entry == "end":
end_label = tkinter.Label(self, "Your score for that round was {} . For another look at your scores go to the scores page".format(score))
end_label.pack()
break
else:
verify(stored_entry)
continue
home_button = ttk.Button(self, text="Go back to home page", command=lambda: shown_frame.show_frame(OpeningFrame))
home_button.pack(pady=10, padx=10)
Here is the error:
File "app.py", line 132, in <module>
app = MyQuiz()
File "app.py", line 21, in __init__
frame = f(main_frame, self)
File "app.py", line 117, in __init__
user_entry = tkinter.Entry(self, "Type your answer here : ")
File "/usr/lib/python3.5/tkinter/__init__.py", line 2519, in __init__
Widget.__init__(self, master, 'entry', cnf, kw)
File "/usr/lib/python3.5/tkinter/__init__.py", line 2138, in __init__
classes = [(k, v) for k, v in cnf.items() if isinstance(k, type)]
AttributeError: 'str' object has no attribute 'items'
Your error is at this line:
user_entry = tkinter.Entry(self, "Type your answer here : ")
because Entry expects only keyword arguments apart from the parent window. So you should replace this line by:
user_entry = tkinter.Entry(self)
user_entry.insert(0, "Type your answer here : ")
Remark: Unlike labels or buttons, entry widgets don't have a text keyword to set the initial text. It has to be set after, using the insert method.

Related name already in use by another Foreign key

I've created a small sqlite3 database using peewee to try to understand foreign keys and get them working in a simple database.
from peewee import *
db = SqliteDatabase('database.db')
class Category(Model):
category = CharField()
class Meta:
database = db
class Subcat(Model):
description = BlobField()
sub_cat = CharField()
top_category = ForeignKeyField(Category, related_name='group')
class Meta:
database = db
db.connect()
db.create_tables([Category, Subcat], safe=True)
I have then created a controller.py file to handle all the database transactions.
(Updated)
from peewee import *
from database import *
class ModCat(Category):
def add_cat(self,category):
update = Category.create(category=category)
def get_cat(self):
categories = Category.select(Category.category).order_by(Category.category)
return categories
class ModSubCat(Subcat):
def save_sub_cat(self, sub, master, desc):
name = Category().select().where(Category.name==master)
update = Subcat.create(sub_cat=sub, top_category=name, description=desc)
Finally, a main.py that allows me to enter data into the database with a simple form created in wxFormBuilder.
from gui import *
from controller import *
class Menu(InDb):
def __init__(self, parent):
InDb.__init__(self, parent)
get_categories = ModCat()
list = get_categories.get_cat()
new_list = []
for thing in list:
new_list.append(thing.category)
print new_list
for f in new_list:
self.m_comboBox1.Append(f)
def click_save( self, event ):
new_cat = ModCat()
new_cat.add_cat(self.m_textCtrl3.GetValue())
self.GetParent() # This assigns parent frame to frame.
self.Close() # This then closes frame removing the main menu.
frame = Menu(None)
frame.Centre()
frame.Show()
def sub_save( self, event ):
sub = self.m_textCtrl5.GetValue()
master = self.m_comboBox1.GetValue()
desc = "Hi"
update = ModSubCat()
update.save_sub_cat(sub, master, desc)
#Start App by calling sub class of MainMenu
if __name__ == '__main__':
app = wx.App(0)
frame = Menu(None)
frame.Centre()
frame.Show()
app.MainLoop()
The database creates with no errors but when I run main.py it always returns this error.
Traceback (most recent call last):
File "C:/Users/********/PycharmProjects/RAMS/main.py", line 2, in <module>
from controller import *
File "C:\Users\********\PycharmProjects\RAMS\controller.py", line 13, in <module>
class ModSubCat(Subcat):
File "C:\Python27\lib\site-packages\peewee.py", line 4710, in __new__
field.add_to_class(cls, name)
File "C:\Python27\lib\site-packages\peewee.py", line 1437, in add_to_class
invalid('The related_name of %(field)s ("%(backref)s") '
File "C:\Python27\lib\site-packages\peewee.py", line 1431, in invalid
raise AttributeError(msg % context)
AttributeError: The related_name of modsubcat.top_category ("group") is already in use by another foreign key.
I've changed related_by value with no luck.
Is the fact that I have a Sub Class ModSubCat in controller.py causing a problem?
Ive removed the related_name='group'
from
top_category = ForeignKeyField(Category, related_name='group') and now all works.
What is the related_name for?

Difficulty creating lxml Element subclass

I’m trying to create a subclass of the Element class. I’m having trouble getting started though.
from lxml import etree
try:
import docx
except ImportError:
from docx import docx
class File(etree.ElementBase):
def _init(self):
etree.ElementBase._init(self)
self.body = self.append(docx.makeelement('body'))
f = File()
relationships = docx.relationshiplist()
title = 'File'
subject = 'A very special File'
creator = 'Me'
keywords = ['python', 'Office Open XML', 'Word']
coreprops = docx.coreproperties(title=title, subject=subject, creator=creator,
keywords=keywords)
appprops = docx.appproperties()
contenttypes = docx.contenttypes()
websettings = docx.websettings()
wordrelationships = docx.wordrelationships(relationships)
docx.savedocx(f, coreprops, appprops, contenttypes, websettings,
wordrelationships, 'file.docx')
When I try to open the document that is outputted from this code, my version of Word (2003 with compatibility pack) gives me the following error: “This file was created by a previous beta version of Word 2007 and cannot be opened in this version.” When I replace the File object with a different Element created with docx.newdocument(), the document comes out fine. Any ideas/advice?
I don't really get why you want to use a separate class named File.
As Michael0x2a said, you did'nt put a document tag, so it won't work (I don't think Word 2007 can read your file too)
But here is the corrected code:
from lxml import etree
try:
import docx
except ImportError:
from docx import docx
class File(object):
def makeelement(tagname, tagtext=None, nsprefix='w', attributes=None,
attrnsprefix=None):
'''Create an element & return it'''
# Deal with list of nsprefix by making namespacemap
namespacemap = None
if isinstance(nsprefix, list):
namespacemap = {}
for prefix in nsprefix:
namespacemap[prefix] = nsprefixes[prefix]
# FIXME: rest of code below expects a single prefix
nsprefix = nsprefix[0]
if nsprefix:
namespace = '{'+nsprefixes[nsprefix]+'}'
else:
# For when namespace = None
namespace = ''
newelement = etree.Element(namespace+tagname, nsmap=namespacemap)
# Add attributes with namespaces
if attributes:
# If they haven't bothered setting attribute namespace, use an empty
# string (equivalent of no namespace)
if not attrnsprefix:
# Quick hack: it seems every element that has a 'w' nsprefix for
# its tag uses the same prefix for it's attributes
if nsprefix == 'w':
attributenamespace = namespace
else:
attributenamespace = ''
else:
attributenamespace = '{'+nsprefixes[attrnsprefix]+'}'
for tagattribute in attributes:
newelement.set(attributenamespace+tagattribute,
attributes[tagattribute])
if tagtext:
newelement.text = tagtext
return newelement
def __init__(self):
super(File,self).__init__()
self.document = self.makeelement('document')
self.document.append(self.makeelement('body'))
f = File()
relationships = docx.relationshiplist()
title = 'File'
subject = 'A very special File'
creator = 'Me'
keywords = ['python', 'Office Open XML', 'Word']
coreprops = docx.coreproperties(title=title, subject=subject, creator=creator,
keywords=keywords)
appprops = docx.appproperties()
contenttypes = docx.contenttypes()
websettings = docx.websettings()
wordrelationships = docx.wordrelationships(relationships)
docx.savedocx(f.document, coreprops, appprops, contenttypes, websettings,
wordrelationships, 'file.docx')

Categories