Adding New Line - json

Here my code. After running the code I get the output with a line. All the scraped data stucked in one line. I put counter and tried to put new line before counter. However my attempts did not work.
import scrapy
from urllib.parse import urljoin
from scrapy import signals
from pydispatch import dispatcher
import json
import csv
import time
import re
import os
class AtasehirSpider(scrapy.Spider):
name = 'atasehir'
allowed_domains = ['www.sahibinden.com','sahibinden.com']
start_urls = ['https://www.sahibinden.com/satilik-daire/istanbul-atasehir-ferhatpasa?address_region=2&sorting=price_asc&price_min=3000000']
counter = 0
item = {}
def parse(self, response):
for ad in response.xpath("//td[#class='searchResultsLargeThumbnail']/a/#href").getall():
time.sleep(2)
ads = response.urljoin(ad)
#print(ads)
yield response.follow(url=ads, callback=self.parseInnerPage)
next_page_url = response.xpath("//ul[#class='pageNaviButtons']/li/a[#title='Sonraki']/#href").extract_first()
nextPage = response.urljoin(next_page_url)
if nextPage is not None:
time.sleep(3)
yield scrapy.Request(nextPage)
def parseInnerPage(self, response):
ilan_no = response.xpath("//ul[#class='classifiedInfoList']/li[1]/span/text()").get()
ilan_tarihi = response.xpath("//ul[#class='classifiedInfoList']/li[2]/span/text()").get()
emlak_tipi = response.xpath("//ul[#class='classifiedInfoList']/li[3]/span/text()").get()
metrekare_brut = response.xpath("//ul[#class='classifiedInfoList']/li[4]/span/text()").get()
metrekare_net = response.xpath("//ul[#class='classifiedInfoList']/li[5]/span/text()").get()
oda_sayisi = response.xpath("//ul[#class='classifiedInfoList']/li[6]/span/text()").get()
bina_yasi = response.xpath("//ul[#class='classifiedInfoList']/li[7]/span/text()").get()
bulundugu_kat = response.xpath("//ul[#class='classifiedInfoList']/li[8]/span/text()").get()
kat_sayisi = response.xpath("//ul[#class='classifiedInfoList']/li[9]/span/text()").get()
isitma = response.xpath("//ul[#class='classifiedInfoList']/li[10]/span/text()").get()
banyo_sayisi = response.xpath("//ul[#class='classifiedInfoList']/li[11]/span/text()").get()
balkon = response.xpath("//ul[#class='classifiedInfoList']/li[12]/span/text()").get()
esyali = response.xpath("//ul[#class='classifiedInfoList']/li[13]/span/text()").get()
kullanim_durumu = response.xpath("//ul[#class='classifiedInfoList']/li[14]/span/text()").get()
site_icerisinde = response.xpath("//ul[#class='classifiedInfoList']/li[15]/span/text()").get()
site_adi = response.xpath("//ul[#class='classifiedInfoList']/li[16]/span/text()").get()
aidat = response.xpath("//ul[#class='classifiedInfoList']/li[17]/span/text()").get()
krediye_uygun = response.xpath("//ul[#class='classifiedInfoList']/li[18]/span/text()").get()
tapu_durumu = response.xpath("//ul[#class='classifiedInfoList']/li[19]/span/text()").get()
kimden = response.xpath("//ul[#class='classifiedInfoList']/li[20]/span/text()").get()
fiyat = response.xpath("//div[#class='classifiedInfo ']/h3[contains(text(), 'TL')]/text()").get()
box = response.xpath("//div[#class='uiBoxContainer classifiedDescription']/ul/li[#class='selected']/text()").getall()
emptystr = ""
for i in box:
emptystr += i+''
emptystr = emptystr.replace("\n", "")
emptystr = emptystr.replace("\t", "")
emptystr = emptystr.replace(u"\u0020", ",")
self.item[self.counter] = {
'ilan_no' : ilan_no.strip(),
'fiyat' : fiyat.strip(),
'kimden' : kimden.strip(),
'tapu_durumu' : tapu_durumu.strip(),
'krediye_uygun' : krediye_uygun.strip(),
'aidat' : aidat.strip(),
'site_adi' : site_adi.strip(),
'site_icerisinde' : site_icerisinde.strip(),
'kullanim_durumu' : kullanim_durumu.strip(),
'esyali' : esyali.strip(),
'balkon' : balkon.strip(),
'banyo_sayisi' : banyo_sayisi.strip(),
'isitma' : isitma.strip(),
'kat_sayisi' : kat_sayisi.strip(),
'bulundugu_kat' : bulundugu_kat.strip(),
'bina_yasi' : bina_yasi.strip(),
'oda_sayisi' : oda_sayisi.strip(),
'metrekare_net' : metrekare_net.strip(),
'metrekare_brut' : metrekare_brut.strip(),
'emlak_tipi' : emlak_tipi.strip(),
'ilan_tarihi' : ilan_tarihi.strip(),
'ozellikler' : emptystr.strip()
}
self.counter = self.counter + 1
#print('item')
with open('ferhatpasa.json', 'w') as fp:
json.dump(self.item, fp)
Here my code. After running the code I get the output with a line. All the scraped data stucked in one line. I put counter and tried to put new line before counter. However my attempts did not work.

Related

Bitbucket Merge script working in Gobal Admin but not in Admin to repository

// import the required libraries
import groovy.json.JsonOutput
import groovyx.net.http.HttpResponseException
import groovy.json.JsonSlurper
//set the commandline arguements in to global variables
def reqUrl = "<Bitbucket URL>"
def branchUAT = "<branchname>"
def branchRelease = "<branchname>"
def projects = mergeRequest.pullRequest.toRef.repository.project.key
String repoString = mergeRequest.pullRequest.toRef.repository
repos = repoString.tokenize("/")[1].tokenize("[")[0]
def branchSource = mergeRequest.pullRequest.fromRef.displayId
def branchDestination = mergeRequest.pullRequest.toRef.displayId
//define the required variables
def UAT_Commits_List = [] as String[]
def JSON_slurper = new groovy.json.JsonSlurper()
if (branchDestination == branchRelease) {
def UAT_Commits_uri_curl = [ 'bash', '-c', "curl https://${reqUrl}/rest/api/1.0/projects/${projects}/repos/${repos}/compare/commits?from=${branchUAT}" ].execute().text
def UAT_Commits_uri_result = JSON_slurper.parseText(UAT_Commits_uri_curl)
try {
def PRApproveArray = UAT_Commits_uri_result.values
PRApproveArray.each {
UAT_Commits_List = UAT_Commits_List + it['id']
}
}
catch(HttpResponseException e) {
catchMethod(e)
}
}
Error: You tried to call a method which is not allowed: groovy.json.JsonSlurper#parseText(java.lang.String)
# line 28, column 32.
def UAT_Commits_uri_result = JSON_slurper.parseText(UAT_Commits_uri_curl)

How to update Kivy labels dynamically after button is pressed

I'm trying to make an app that uses data from MySQL server. So far I was doing fine, until I stumbled accross a need to update the Labels.
This is what I have so far:
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.clock import Clock
import MySQLdb
class MainView(ScrollView):
def qchange(self):
query = 'SELECT * FROM `citiestovisit` ORDER BY `idcitiestovisit`'
self.db_data(query)
q = 'SELECT * FROM `citiestovisit` ORDER BY `Name`'
def db_data(self, query=q):
#vector = ListProperty()
vector = []
con = MySQLdb.connect(host="localhost", user="root", passwd="", db="cities")
cur = con.cursor()
cur.execute('SET NAMES `utf8`')
cur.execute(query)
result = cur.fetchall()
for row in result:
string = str(row[0]) + " " + str(row[1]) + " " + str(row[2])
vector.append(string)
print vector
return vector
def __init__(self, **kwargs):
kwargs['cols'] = 2
super(MainView, self).__init__(**kwargs)
GL = GridLayout(cols = 3, spacing=10, size_hint_y=None)
GL.bind(minimum_height=GL.setter('height'))
for row in self.db_data():
splitRow = row.split(" ")
for data in splitRow:
GL.add_widget(Label(text=data,size_hint_y=None, font_size='20sp'))
self.add_widget(GL)
Builder.load_string("""
<MenuScreen>:
BoxLayout:
GridLayout:
cols: 1
Button:
text: 'Goto settings'
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'settings'
Button:
text: 'Quit'
Label:
font_name: 'C:\Anonymous\Anonymous.ttf'
text: "picture here"
<SettingsScreen>:
""")
# Declare both screens
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
ss = SettingsScreen(name='settings')
layout = BoxLayout(orientation='vertical')
BL = BoxLayout()
layout.add_widget(BL)
#Instance of a MainView class
MV = MainView()
def callback(instance):
sm.transition.direction = 'right'
sm.current = 'menu'
def callback2(instance):
MV.qchange()
btn = Button(text="Back to Menu")
btn.bind(on_press=callback)
btn.size_hint = (1, 0.3)
BL.add_widget(btn)
btn2 = Button(text="Sort by ID")
btn2.size_hint = (1, 0.3)
btn2.bind(on_press=callback2)
BL.add_widget(btn2)
layout.add_widget(MainView())
sublayout = GridLayout(cols=3)
sublayout.add_widget(Label(text="hello"))
sublayout.add_widget(Label(text="World"))
sublayout.add_widget(Label(text="Python"))
layout.add_widget(sublayout)
ss.add_widget(layout)
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(ss)
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
I'm particularly interested in def qchange(self) mehod as it passes into def db_data(self, query=q) a new query; as a result request is sent to the database and an array of strings is returned. However, this array is not proccessed any further and labels in GL widget are not updated. I think I need to add the clock that would call the __init__ in MainView, but it's only a guess as I've also read about using properties (which I don't know how to use here as well)
I've eddited my code. Now it looks like this:
class MainView(ScrollView):
def qchange(self):
query = 'SELECT * FROM `citiestovisit` ORDER BY `idcitiestovisit`'
#self.db_data(query)
#LG = self.LabelsGrid(self.GL)
q = 'SELECT * FROM `citiestovisit` ORDER BY `Name`'
def db_data(self, query=q):
vector = []
con = MySQLdb.connect(host="localhost", user="root", passwd="", db="cities")
cur = con.cursor()
cur.execute('SET NAMES `utf8`')
cur.execute(query)
result = cur.fetchall()
for row in result:
string = str(row[0]) + " " + str(row[1]) + " " + str(row[2])
vector.append(string)
print vector
return vector
class LabelsGrid(GridLayout):
def __init__(self, **kwargs):
self.cols = 3
self.spacing = 10
self.size_hint_y = None
def show_labels(self, strings):
self.clear_widgets()
for row in strings:
splitRow = row.split(" ")
for data in splitRow:
label = Label(text=data, size_hint_y=None, font_size='20sp')
self.add_widget(label)
GL = LabelsGrid()
def __init__(self, **kwargs):
kwargs['cols'] = 2
super(MainView, self).__init__(**kwargs)
self.GL=self.LabelsGrid()
# GL = GridLayout(cols = 3, spacing=10, size_hint_y=None)
self.GL.bind(minimum_height=self.GL.setter('height'))
self.GL.show_labels(self.db_data(self.q))
self.add_widget(self.GL)
#self.GL.clear_widgets()
Builder.load_string("""
<MenuScreen>:
BoxLayout:
GridLayout:
cols: 1
Button:
text: 'Goto settings'
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'settings'
Button:
text: 'Quit'
Label:
font_name: 'C:\Anonymous\Anonymous.ttf'
text: "picture here"
<SettingsScreen>:
""")
# Declare both screens
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
ss = SettingsScreen(name='settings')
layout = BoxLayout(orientation='vertical')
BL = BoxLayout()
layout.add_widget(BL)
#Instance of a MainView class
MV = MainView()
def callback(instance):
sm.transition.direction = 'right'
sm.current = 'menu'
def callback2(instance):
MV.qchange()
btn = Button(text="Back to Menu")
btn.bind(on_press=callback)
btn.size_hint = (1, 0.3)
BL.add_widget(btn)
btn2 = Button(text="Sort by ID")
btn2.size_hint = (1, 0.3)
btn2.bind(on_press=callback2)
BL.add_widget(btn2)
layout.add_widget(MainView())
sublayout = GridLayout(cols=3)
sublayout.add_widget(Label(text="hello"))
sublayout.add_widget(Label(text="World"))
sublayout.add_widget(Label(text="Python"))
layout.add_widget(sublayout)
ss.add_widget(layout)
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(ss)
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
By adding
class LabelsGrid(GridLayout):
def __init__(self, **kwargs):
self.cols = 3
self.spacing = 10
self.size_hint_y = None
def show_labels(self, strings):
self.clear_widgets()
for row in strings:
splitRow = row.split(" ")
for data in splitRow:
label = Label(text=data, size_hint_y=None, font_size='20sp')
self.add_widget(label)
I wanted to add custom GridLayout according to a given piece of advice, however, now I get an error saying:
AttributeError: 'LabelsGrid' object has no attribute '_trigger_layout'
Any ideas on how to handle this?
Create a custom grid layout, let's say LabelsGrid, and in the class implement a method show_labels. Example:
class LabelsGrid(GridLayout):
def show_labels(self, strings):
self.clear_widgets()
for text in strings:
label = Label(text=text)
self.add_widget(label)
This way, each time you call the method with names of labels in a list, it will update itself.

Status code error while fetching JSON data

I am trying to Extract JSON data from URL with parameters to it and code is as follows:
import json
from flask import Flask, render_template, request, jsonify
import requests
app = Flask(__name__)
import urllib2
#app.route("/",methods=['GET','POST'])
def home():
if request.method == 'POST':
#user inputs
valueone= request.form.get('first')
valueTwo = request.form.get('second')
valueThree = request.form.get('third')
#api call
data = {"perfid" : {0}, "section" : {"hostname" : {1}, "iteration" : {2}, "sectionname" : "sysstat_M"}}
req = urllib2.Request('http://api-latx-dev.corp.netapp.com/ws/spm/spm-general', json.dumps(data))
response = urllib2.urlopen(req)
the_page = response.read()
url=response.getcode()
returnData = {}
if url.status_code == 200:
returnData["status"] = "SUCCESS"
returnData["result"] = the_page
return jsonify(returnData)
else:
returnData["status"] = "ERROR"
return jsonify(returnData)
#jsonify(response.json())
return render_template('index.html')
I need to fetch data But getcode() gives int which is not working with "if url.status_code == 200".Can anyone please suggest how to deal with it.

Why Field names are sliced and raise error in python csv writing

During practicing selenium i failed to write a dictionary into csv.I have searched the problem solution like it but it did not help me. My problem is when i want to write a python dictionary into csv file using dictwriter i reach at exception i.e.
ValueError: dict contains fields not in fieldnames: u'S', u'k', u'u'
but the field name is
Sku
Why it is sliced and gives me queer exception but i supplied proper filednames in the dictwriter.
My experimenting code. is-
import os,sys,bs4,random,codecs,requests
import unicodecsv as csv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from contextlib import contextmanager
from selenium.webdriver.support.expected_conditions import staleness_of
from selenium.webdriver.support import expected_conditions as EC
current_file = sys.argv[0]
link_dir = os.path.dirname(current_file)
link_path = os.path.join(link_dir,'lnks.txt')
Image_folder = os.path.join(link_dir,"images")+"\\"
urls = [line.strip() for line in open(link_path, 'r')]
urls = list(set(urls))
url = urls[0]
driver = webdriver.Firefox()#Chrome()##chromedriver)##
base_url = 'http://www.hotleathers.com'
Header = [u'Url',u'Name',u'Sku',u'Price',u'Color',u'Size']
#def get_data(url):
#try:
print "Scraping : %s"%url
driver.get(url)
driver.implicitly_wait(3)
detpage_lnks = driver.find_elements_by_xpath("//div[#style='margin-top:0px;margin-bottom:5px']/a")
detpage_lnks = map(lambda x: x.get_attribute('href'),detpage_lnks)
for i in detpage_lnks:
Data = []
#try:
driver.get(i)
driver.implicitly_wait(3)
Name_v=driver.find_element_by_xpath("//table [#class='showproductpage']/tbody/tr/td/h1").text
Sku_v=driver.find_element_by_xpath("(//table[#cellspacing = '0'])[3]//td[#style='padding-left:5px; font-size:16px; font-weight:bold;']").text
image_name = Sku_v+".jpg"
image_url = "http://www.hotleathers.com/Assets/ProductImages/large/"+image_name
res = requests.get(image_url)
if res.status_code == requests.codes.ok:
out = open(Image_folder+image_name,'wb')
out.write(res.content)
Price_v=driver.find_element_by_xpath("((//table[#cellspacing = '0'])[3]//tr)[2]//span").text
Color=driver.find_elements_by_xpath("(//table[#class='buyProductForm'])//tr[2]/td/select/option")
Color_v = '"'+':'.join([i.text for i in Color[1:]])+'"'
Size=driver.find_elements_by_xpath("(//table[#class='buyProductForm'])//tr[3]/td/select/option")
Size_v = '"'+':'.join([i.text for i in Size[1:]])+'"'
temp = [driver.current_url,Name_v,Sku_v,Price_v,Color_v,Size_v]
Data.append(zip(Header,temp))
Data = [item for sublst in Data for item in sublst]
my_dict = dict(Data)
with codecs.open(os.path.join(link_dir,"Image_info.csv"),'wb',encoding="utf-8") as f:
# Using dictionary keys as fieldnames for the CSV file header
writer = csv.DictWriter(f,delimiter=",", fieldnames=Header,lineterminator='\n')
writer.writeheader()
for d in my_dict:
writer.writerow(d)
driver.close()
I tried both unicodecsv and csv but with no success.
After many tries i found solution as below-
I did not understand that writerow expects a dictionary!
import os,sys,bs4,random,codecs,requests
import unicodecsv as csv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from contextlib import contextmanager
from selenium.webdriver.support.expected_conditions import staleness_of
from selenium.webdriver.support import expected_conditions as EC
current_file = sys.argv[0]
link_dir = os.path.dirname(current_file)
link_path = os.path.join(link_dir,'lnks.txt')
Image_folder = os.path.join(link_dir,"images")+"\\"
urls = [line.strip() for line in open(link_path, 'r')]
urls = list(set(urls))
url = urls[0]
driver = webdriver.Firefox()#Chrome()##chromedriver)##
base_url = 'http://www.hotleathers.com'
Header = [u'Url',u'Name',u'Sku',u'Price',u'Color',u'Size']
#def get_data(url):
#try:
print "Scraping : %s"%url
driver.get(url)
driver.implicitly_wait(3)
detpage_lnks = driver.find_elements_by_xpath("//div[#style='margin-top:0px;margin-bottom:5px']/a")
detpage_lnks = map(lambda x: x.get_attribute('href'),detpage_lnks)
for i in detpage_lnks:
Data = []
#try:
driver.get(i)
driver.implicitly_wait(3)
Name_v=driver.find_element_by_xpath("//table [#class='showproductpage']/tbody/tr/td/h1").text
Sku_v=driver.find_element_by_xpath("(//table[#cellspacing = '0'])[3]//td[#style='padding-left:5px; font-size:16px; font-weight:bold;']").text
image_name = Sku_v+".jpg"
image_url = "http://www.hotleathers.com/Assets/ProductImages/large/"+image_name
res = requests.get(image_url)
if res.status_code == requests.codes.ok:
out = open(Image_folder+image_name,'wb')
out.write(res.content)
Price_v=driver.find_element_by_xpath("((//table[#cellspacing = '0'])[3]//tr)[2]//span").text
Color=driver.find_elements_by_xpath("(//table[#class='buyProductForm'])//tr[2]/td/select/option")
Color_v = '"'+':'.join([i.text for i in Color[1:]])+'"'
Size=driver.find_elements_by_xpath("(//table[#class='buyProductForm'])//tr[3]/td/select/option")
Size_v = '"'+':'.join([i.text for i in Size[1:]])+'"'
temp = [driver.current_url,Name_v,Sku_v,Price_v,Color_v,Size_v]
Data.append(zip(Header,temp))
Data = [item for sublst in Data for item in sublst]
my_dict = dict(Data)
with codecs.open(os.path.join(link_dir,"Image_info.csv"),'ab',encoding="utf-8") as f:
# Using dictionary keys as fieldnames for the CSV file header
writer = csv.DictWriter(f,fieldnames=my_dict.keys())
writer.writerow(my_dict)
driver.close()

Serialize Gtk TreeStore / ListStore using JSON

I made a new example which shows much better what I am trying to do. The new example gives the following ouput. Is there a way that the data can go into the respective store key (the {} brackets)?
{
"copy": [
[
[
5.0,
8.0,
9.0
]
],
[
[
4.0,
0.0,
1.0
]
]
],
"name": "dataset1",
"sets": [
{
"store": {},
"type": "vector"
},
{
"store": {},
"type": "vector"
}
]
}
New example
from gi.repository import Gtk
import json
import random
class Vector(object):
def __init__(self, data):
self.store = Gtk.ListStore(float, float, float)
self.store.append([data[0], data[1], data[2]])
self.type = "vector"
def return_data(self):
store_data = []
def iterate_over_data(model, path, itr):
row = model[path]
store_data.append([row[0], row[1], row[2]])
self.store.foreach(iterate_over_data)
return store_data
class DataSet(object):
def __init__(self, name):
self.name = name
self.sets = []
def add_vector(self):
data = [random.randint(0,9) for x in range(3)]
self.sets.append(Vector(data))
def to_json(self):
self.copy = []
for s in self.sets:
self.copy.append(s.return_data())
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=True, indent=4)
obj1 = DataSet("dataset1")
for x in range(2):
obj1.add_vector()
print(obj1.to_json())
Old example
I am currently figuring out how to serialize a Gtk ListStore that is nested in a Gtk TreeStore. I got a small example to work, but am not sure if this approach will scale for programs that have more data attached (For example the layer object could hold a color or a date of creation). Is there maybe another way to to this?
My current approach is to gather the data in list and dictionary form myself and then just create the JSON-dump. I have the feeling that this would be rather difficult to maintain if I need to attach 25 values to each layer-object.
from gi.repository import Gtk, Gdk
import json
import random
class LayerTreeView(Gtk.TreeView):
def __init__(self, store):
Gtk.TreeView.__init__(self, store)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Name", renderer, text=0)
self.append_column(column)
class DataTreeView(Gtk.TreeView):
def __init__(self, store):
Gtk.TreeView.__init__(self, store)
self.store = store
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Data", renderer, text=0)
self.append_column(column)
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TreeView Serialize")
self.connect("delete-event", Gtk.main_quit)
self.set_border_width(10)
self.set_default_size(400, 300)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6, expand=True)
self.add(vbox)
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
button = Gtk.Button("Cut")
button.connect("clicked", self.on_cut_clicked)
hbox.pack_start(button, True, True, 0)
button = Gtk.Button(stock=Gtk.STOCK_COPY)
button.connect("clicked", self.on_copy_clicked)
hbox.pack_start(button, True, True, 0)
button = Gtk.Button(stock=Gtk.STOCK_PASTE)
button.connect("clicked", self.on_paste_clicked)
hbox.pack_start(button, True, True, 0)
vbox.add(hbox)
self.layer_store = Gtk.TreeStore(str, object, object)
self.layer_view = LayerTreeView(self.layer_store)
self.layer_sw = Gtk.ScrolledWindow()
self.data_sw = Gtk.ScrolledWindow()
self.layer_sw.add(self.layer_view)
treebox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6, expand=True)
treebox.pack_start(self.layer_sw, True, True, 0)
treebox.pack_start(self.data_sw, True, True, 0)
vbox.add(treebox)
self.select = self.layer_view.get_selection()
self.select.connect("changed", self.on_selection_changed)
self.add_test_data()
def add_test_data(self):
for x in range(3):
data_store = Gtk.ListStore(str)
data_view = DataTreeView(data_store)
for y in range(5):
data_store.append([str(y+x)])
self.layer_store.append(None, ["Data {}".format(x), data_store, data_view])
def on_selection_changed(self, selection):
"""
When layer is switched load respective data
"""
model, treeiter = selection.get_selected()
if treeiter != None:
data_view = model[treeiter][2]
child = self.data_sw.get_child()
if child != None:
self.data_sw.remove(self.data_sw.get_child())
self.data_sw.add(data_view)
self.show_all()
def on_cut_clicked(self, button):
pass
def on_copy_clicked(self, button):
copy_list = ["safe-to-paste"]
data_dict = {}
for row in self.layer_store:
name = row[0]
data_obj = row[1]
value_list = []
for datarow in data_obj:
value = datarow[0]
value_list.append(value)
data_dict[name] = value_list
copy_list.append(data_dict)
data = json.dumps(copy_list)
self.clipboard.set_text(data, -1)
def on_paste_clicked(self, button):
paste_str = self.clipboard.wait_for_text()
try:
parse = json.loads(paste_str)
json_str = True
except:
json_str = False
if json_str is False:
return
keyword = parse[0]
if keyword != "safe-to-paste":
return
data_dict = parse[1]
for x in data_dict:
data_list = data_dict[x]
data_store = Gtk.ListStore(str)
data_view = DataTreeView(data_store)
for y in data_list:
data_store.append([str(y)])
self.layer_store.append(None, [x, data_store, data_view])
win = MainWindow()
win.show_all()
Gtk.main()
I have an improved version of your code with dict comprehension and #staticmethod that makes the signal callbacks more readable and shorter. Nevertheless, this does not really solve your problem as it still generates the json manually. If the ListStore gets more complex, it would probably be better to let the DataListStore class generate its own json with a corresponding method.
from gi.repository import Gtk, Gdk
import json
class LayerTreeView(Gtk.TreeView):
def __init__(self, store):
Gtk.TreeView.__init__(self, store)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Name", renderer, text=0)
self.append_column(column)
class DataTreeView(Gtk.TreeView):
def __init__(self):
Gtk.TreeView.__init__(self)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Data", renderer, text=0)
self.append_column(column)
class DataListStore(Gtk.ListStore):
#staticmethod
def from_json(*args, values=[]):
store = DataListStore(*args)
for value in values:
store.append((value,))
return store
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TreeView Serialize")
self.connect("delete-event", Gtk.main_quit)
self.set_border_width(10)
self.set_default_size(400, 300)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6, expand=True)
self.add(vbox)
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
button = Gtk.Button("Cut")
button.connect("clicked", self.on_cut_clicked)
hbox.pack_start(button, True, True, 0)
button = Gtk.Button(stock=Gtk.STOCK_COPY)
button.connect("clicked", self.on_copy_clicked)
hbox.pack_start(button, True, True, 0)
button = Gtk.Button(stock=Gtk.STOCK_PASTE)
button.connect("clicked", self.on_paste_clicked)
hbox.pack_start(button, True, True, 0)
vbox.add(hbox)
self.layer_store = Gtk.TreeStore(str, object)
self.layer_view = LayerTreeView(self.layer_store)
self.data_view = DataTreeView()
layer_sw = Gtk.ScrolledWindow()
layer_sw.add(self.layer_view)
data_sw = Gtk.ScrolledWindow()
data_sw.add(self.data_view)
treebox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6, expand=True)
treebox.pack_start(layer_sw, True, True, 0)
treebox.pack_start(data_sw, True, True, 0)
vbox.add(treebox)
select = self.layer_view.get_selection()
select.connect("changed", self.on_selection_changed)
self.add_test_data()
def add_test_data(self):
for x in range(3):
data_list = [str(y+x) for y in range(5)]
self.layer_store.append(None, ["Data {}".format(x), data_list])
def on_selection_changed(self, selection):
"""
When layer is switched load respective data
"""
model, treeiter = selection.get_selected()
if treeiter != None:
self.data_view.set_model(
DataListStore.from_json(str, values=model[treeiter][1])
)
def on_cut_clicked(self, button):
pass
def on_copy_clicked(self, button):
copy_list = [
'safe-to-paste',
{row[0]: row[1] for row in self.layer_store},
]
data = json.dumps(copy_list)
self.clipboard.set_text(data, -1)
def on_paste_clicked(self, button):
paste_str = self.clipboard.wait_for_text()
try:
parse = json.loads(paste_str)
except:
return
if parse[0] != "safe-to-paste":
return
data_dict = parse[1]
for x in data_dict:
self.layer_store.append(None, [x, data_dict[x]])
win = MainWindow()
win.show_all()
Gtk.main()