How to read all gtk.TreeModelRow (in Python) - python

I have a gtkTreeView with this model structure:
Row One
.. Child One
....Grandson On
....Grandson Two
Row Two
..Child One
I need to read each one of this rows.
How can I do?
I'm a new bee in gtk.

I solved my own problem above with this code:
def print_tree_store(store):
rootiter = store.get_iter_first()
print_rows(store, rootiter, "")
def print_rows(store, treeiter, indent):
while treeiter != None:
print indent + str(store[treeiter][:])
if store.iter_has_child(treeiter):
childiter = store.iter_children(treeiter)
print_rows(store, childiter, indent + "\t")
treeiter = store.iter_next(treeiter)
Is part of this documentation
Tree and List Widgets

Related

Get the structure of the folders from the given path list as strings

Given a list of paths as:
'alpha/beta/gamma/delta alpha/beta/sigma beta/phi/pi/rho'
I want to Print it as:
-alpha
-beta
-gamma
delta
-sigma
-beta
-phi
-pi
rho
Can you please help me out with this?
I was able to make a list of dictionaries of dictionaries. (I am kinda lost here)
There are simpler ways to do this where I can directly print the data but I want to do it in a structure such that I might be able to use this data somewhere else too.
paths = 'alpha/beta/gamma/delta alpha/beta/sigma b/f/g/h r/g/t/y q/w/er/rat'
folder_list = []
def get_children(ippath, e_dict):
remaining_path = '/'.join(ippath.split('/')[1:])
try:
splitted_path = ippath.split('/')[0]
if splitted_path:
e_dict[splitted_path] = {}
e_dict[splitted_path].update(get_children(remaining_path, e_dict[ippath.split('/')[0]]))
return e_dict
else:
return e_dict
except:
return remaining_path
for path in paths.split(' '):
end_dict = dict()
output = get_children(path, end_dict)
if output:
folder_list.append(output)
# final_list.update(output)
else:
continue
print(folder_list)
It gives me a list of nested dictionaries but still not what I want.
Thank you, I really appreciate the help
Are you fine with using another library? if so, dpath will work great for this.
It allows you to create dicts based on strings
https://pypi.org/project/dpath/
Here's a straightforward solution:
First, build a set of all distinct full paths, including the intermediate paths.
Sort the paths. This puts them in depth-first order, guaranteeing that a parent directory will always appear before its children.
Iterate through the paths, maintaining a stack:
Pop from the stack until you find the parent of the current path.
Print just the difference between the current path and its parent. The indentation level is determined by the length of the stack.
Push the current path to the stack.
To get the - symbols in the right place, we can keep track of which paths are leaf nodes in the tree. Here's the code:
def dir_tree(s):
paths = set()
for path in s.split():
parts = path.split('/')
is_leaf = True
while parts:
path = '/'.join(parts) + '/'
paths.add( (path, is_leaf) )
parts.pop()
is_leaf = False
stack = ['']
for path, is_leaf in sorted(paths):
while not path.startswith(stack[-1]):
stack.pop()
suffix = path[len(stack[-1]):-1]
tabs = len(stack) - 1
print('\t'*tabs + ('' if is_leaf else '-') + suffix)
stack.append(path)
Output:
-alpha
-beta
-gamma
delta
sigma
-beta
-phi
-pi
rho
I finally got it to work.. :)
Ron Serruya's suggested library helped me rethink my structure.
import json
paths = 'alpha/beta/gamma/delta alpha/beta/sigma beta/phi/pi/rho'
folder_list = {}
def get_children(ippath, e_dict):
remaining_path = '/'.join(ippath.split('/')[1:])
try:
splitted_path = ippath.split('/')[0]
if splitted_path:
e_dict[splitted_path] = {}
e_dict[splitted_path].update(get_children(remaining_path, e_dict[ippath.split('/')[0]]))
return e_dict
else:
return e_dict
except:
return remaining_path
def merge_dictionaries(new_dictionary, main_dictionary):
key = list(new_dictionary.keys())[0]
if list(new_dictionary[key].keys())[0] in list(main_dictionary[key].keys()):
merge_dictionaries(new_dictionary[key], main_dictionary[key])
else:
main_dictionary[key][list(new_dictionary[key].keys())[0]] = new_dictionary[key][list(new_dictionary[key].keys())[0]]
def main():
for path in paths.split(' '):
end_dict = dict()
output = get_children(path, end_dict)
if output:
if list(output.keys())[0] not in list(folder_list.keys()):
folder_list.update(output)
else:
merge_dictionaries(output, folder_list)
else:
continue
print(str(json.dumps(folder_list, sort_keys=True, indent=4, separators=('', ''))).replace('{', '').replace('}', ''))
main()
Gives Output:
"alpha"
"beta"
"gamma"
"delta"
"sigma"
"beta"
"phi"
"pi"
"rho"
Sorry for really bad structure of the code, I am up for suggestion to improve this structurally.

Iterating a GTK3 Treestore with child nodes in python

im trying to search a GTK 3 treestore for a string. The treestore has 4 columns,and is for a treeview widget that has callapsible nodes. im creating the nodes with this function:
def AddItem(self,ParentIter,txt,datapath='',projName=Project):
self.store = self.builder.get_object('theTreeStore')
NodeId = secrets.token_hex(8)
if ParentIter == None:
ParentNodeId = ''
else:
ParentNodeId = self.store.get_value(ParentIter, 2)
treeEntry = ['%s' %ParentNodeId,'%s' %txt,'%s' %NodeId,'%s' %datapath]
node = self.store.append(ParentIter, treeEntry) <<<<<<<<<<<<<
self.view = self.builder.get_object('Tree')
self.view.set_model(self.store)
# table nodes(tParentNodeID ,tNodeTxt ,tNodeID ,tDataPath );
sql = "INSERT INTO %s (tParentNodeID ,tNodeTxt ,tNodeID ,tDataPath ) VALUES ('%s','%s','%s','%s')" %(projName,ParentNodeId,txt,NodeId,datapath)
self.cursor.execute(sql)
self.mariadb_connection.commit()
for x in self.cursor:
print(x)
return(node)
as you can see the data in the tree is nested in its parent.
now i need to somehow search the treestore for a row that contains a certain NodeId string. Ive read the gtk docs over and over but i cant quite figure out what to do. im guessing i need to use following methods:
store.get_iter()
store.iter_children()
but idk everything i try only returns the root nodes no children.
i basically want a search function that will recursively search each node and its children,and their children for a string. something like this:
def GetRowbyNodeID(nodeid):
for row in treestore:
if row[1]==nodeid:
return(row)
for children in row:
if children[1] == nodeid
return(children)
The code is in multiple files, i can post any functions relevant if needed.
GtkTreeStore implements GtkTreeModel interface. Thus you can use the following methods:
iter = store.get_iter() to obtain an iterator
chld_iter = iter.get_children()to obtain an iterator over children elements (please note, it's an iter's method!)
I'd also recommend reading this tutorial. "The Model" section contains all you need on iterating over the model (spoiler: search for print_tree_store)
Got it all working. thanks again. im posting the relevant code just in case anyone else could use it.
def SearchTreeRows(self,store, treeiter, searchstr):
print("\nsearch>%s"%searchstr)
while treeiter != None:
if store[treeiter][2] ==searchstr:
print("found in:%s"%str(store[treeiter][:]))
return(treeiter)
break
print("searched:%s"%str(store[treeiter][:]))
if store.iter_has_child(treeiter):
childiter = store.iter_children(treeiter)
ret = self.SearchTreeRows(store, childiter, searchstr)
if ret is not None:
return ret
treeiter = store.iter_next(treeiter)
def NodeId2Tree(self,nodeid):
self.store = self.builder.get_object('theTreeStore')
rootiter = self.store.get_iter_first()
row = self.SearchTreeRows(self.store, rootiter,nodeid)
return(row)
def LoadProject(self):
global Project
global ProjSel
sql = "SHOW TABLES"
self.cursor.execute(sql)
tbls = []
for x in self.cursor:
tbls.append(x)
diag = self.builder.get_object('ProjectChooser')
self.combo = Gtk.ComboBox()
ls =Gtk.ListStore(str)
for tble in tbls:
strg ="%s" %tble
ls.append(tble)
self.combo.set_model(ls)
cellr = Gtk.CellRendererText()
self.combo.pack_start(cellr,True)
self.combo.add_attribute(cellr, 'text', 0)
diag.vbox.pack_start(self.combo, True, True, 5)
diag.show_all()
response = diag.run()
self.combo.destroy()
print(ProjSel)
Project = ProjSel
ProjSel = ''
view = self.builder.get_object('Tree')
self.store.clear()
view.set_model(self.store)
sql = "SELECT tParentNodeId,tNodeTxt,tNodeId FROM %s"%(Project)
self.cursor.execute(sql)
for x in self.cursor:
parid = x[0]
nodtxt = x[1]
nodid =x[2]
if parid == '':
treeEntry = ['%s' %parid, '%s' %nodtxt, '%s' %nodid, '']
node = self.store.append(None, treeEntry) #root nodes
else:
treeEntry = ['%s' %parid, '%s' %nodtxt, '%s' %nodid, '']
n2id = self.NodeId2Tree(parid)
node = self.store.append(n2id, treeEntry)
print("got return:%s For:%s"%(n2id,treeEntry[0]))
view.set_model(self.store)
#select * where parentid == none >> get root nodes ???? or parse line by line

How to store the HTML within an opening and closing tag with Python

I am reading in an HTML document and want to store the HTML nested within a div tag of a certain name, while maintaining its structure (the spacing). This is for the ability convert an HTML doc into components for React. I am struggling with how to store the structure of the nested HTML, and locate the correct closing tag for the div the denotes that everything nested within it will become a React component (div class='rc-componentname' is the opening tag). Any help would be very appreciated. Thanks!
Edit: I assume regex are the best way to go about this. I haven't used regex before so if that is correct someone could point me in the right direction for the expression used in this context that would be great.
import os
components = []
class react_template():
def __init__(self, component_name): # add nested html as second element
self.Import = "import React, { Component } from ‘react’;"
self.Class = "Class " + component_name + ' extends Component {'
self.Render = "render() {"
self.Return = "return "
self.Export = "Default export " + component_name + ";"
def react(component):
r = react_template(component)
if not os.path.exists('components'): # create components folder
os.mkdir('components')
os.chdir('components')
if not os.path.exists(component): # create folder for component
os.mkdir(component)
os.chdir(component)
with open(component + '.js', 'wb') as f: # create js component file
for j_key, j_code in r.__dict__.items():
f.write(j_code.encode('utf-8') + '\n'.encode('utf-8'))
f.close()
def process_html():
with open('file.html', 'r') as f:
for line in f:
if 'rc-' in line:
char_soup = list(line)
for index, char in enumerate(char_soup):
if char == 'r' and char_soup[index+1] == 'c' and char_soup[index+2] == '-':
sliced_soup = char_soup[int(index+3):]
c_slice_index = sliced_soup.index("\'")
component = "".join(sliced_soup[:c_slice_index])
components.append(component)
innerHTML(sliced_soup)
# react(component)
def innerHTML(sliced_soup): # work in progress
first_closing = sliced_soup.index(">")
sliced_soup = "".join(sliced_soup[first_closing:]).split(" ")
def generate_components(components):
for c in components:
react(c)
if __name__ == "__main__":
process_html()
I see you've used the word soup in your code... maybe you've already tried and disliked BeautifulSoup? If you haven't tried it, I'd recommend you look at BeautifulSoup instead of attempting to parse HTML with regex. Although regex would be sufficient for a single tag or even a handful of tags, markup languages are deceptively simple. BeautifulSoup is a fine library and can make things easier for dealing with markup.
https://www.crummy.com/software/BeautifulSoup/bs4/doc/
This will allow you to treat the entirety of your html as a single object and enable you to:
# create a list of specific elements as objects
soup.find_all('div')
# find a specific element by id
soup.find(id="custom-header")

PyQt5: Problems naming a row after using insertRow()

I am trying to create a button that adds a row to a table (QtTableWidget) and uses a dialog box to ask for the name, and I have hit a big problem (seemingly a flaw within PyQt).
By adding a row using the insertRow() function the row header automatically has a value of none, which then means you cannot use the verticalHeaderItem(rowPosition).setText(...) on the row Header as it cannot set the text of an item with value none.
The relevant code is here:
def RenameRow(self, i, name):
self.tab1table.verticalHeaderItem(i).setText(name)
def DatabaseAddRow(self):
text, ok = QInputDialog.getText(self, "Row Entry", 'Please Enter A Row Name:', QLineEdit.Normal, 'e.g. ECN 776')
if ok and text != '':
rowPosition = self.tab1table.rowCount()
self.tab1table.insertRow(rowPosition)
self.RenameRow(rowPosition, text)
Any Ideas how to get around this or maybe methods I do not know about?
So I managed to solve this myself just after asking this after wasting half a day on this problem, such is life. The solution to the problem is to assign an empty item to the header and then rename it, the implementation is here:
def RenameRow(self, i, name, table):
item = QTableWidgetItem()
table.setVerticalHeaderItem(i, item)
item = table.verticalHeaderItem(i)
item.setText(QCoreApplication.translate("MainWindow", name))

Python dictionary editing entries

def replace_acronym(): # function not yet implemented
#FIND
for abbr, text in acronyms.items():
if abbr == acronym_edit.get():
textadd.insert(0,text)
#DELETE
name = acronym_edit.get().upper()
name.upper()
r =dict(acronyms)
del r[name]
with open('acronym_dict.py','w')as outfile:
outfile.write(str(r))
outfile.close() # uneccessary explicit closure since used with...
message ='{0} {1} {2} \n '.format('Removed', name,'with its text from the database.')
display.insert('0.0',message)
#ADD
abbr_in = acronym_edit.get()
text_in = add_expansion.get()
acronyms[abbr_in] = text_in
# write amended dictionary
with open('acronym_dict.py','w')as outfile:
outfile.write(str(acronyms))
outfile.close()
message ='{0} {1}:{2}{3}\n '.format('Modified entry', abbr_in,text_in, 'added')
display.insert('0.0',message)
I am trying to add the functionality of editing my dictionary entries in my tkinter widget. The dictionary is in the format {ACRONYM: text, ACRONYM2: text2...}
What I thought the function would achieve is to find the entry in the dictionary, delete both the acronym and its associated text and then add whatever the acronym and text have been changed to. What happens is for example if I have an entry TEST: test and I want to modify it to TEXT: abc what is returned by the function is TEXT: testabc - appending the changed text although I have (I thought) overwritten the file.
What am I doing wrong?
That's a pretty messy lookin' function. The acronym replacement itself can be done pretty simple:
acronyms = {'SONAR': 'SOund Navigation And Ranging',
'HTML': 'HyperText Markup Language',
'CSS': 'Cascading Style Sheets',
'TEST': 'test',
'SCUBA': 'Self Contained Underwater Breathing Apparatus',
'RADAR': 'RAdio Detection And Ranging',
}
def replace_acronym(a_dict,check_for,replacement_key,replacement_text):
c = a_dict.get(check_for)
if c is not None:
del a_dict[check_for]
a_dict[replacement_key] = replacement_text
return a_dict
new_acronyms = replace_acronym(acronyms,'TEST','TEXT','abc')
That works perfect for me (in Python 3). You could just call this in another function that writes the new_acronyms dict into the file or do whatever else you want with it 'cause it's no longer tied to just being written to the file.

Categories