a standard Gramps install doesnât have pandas. So ran with your sample code and worked out a converter that work in the Python Evaluation gramplet and uses the Gtk file chooser.
Key .json
files are the addons_xx.json files⌠but more and more Gramps files are switching to .json format. So such a tool will gain value in the future. I suppose the next step is to wrap it in a Gramplet shell. (Since it is likely that a series of conversions would performed⌠the addons JSON in english, french, german, et cetera⌠then Tools would be tedious. Learned that from the tedium of doing a series of WebConnection lookups from a context menu. Those lookups would be a lot more convenient as a Gramplet.)
I wonât be able to contribute it as an addon since Perplexity AI did most of the heavy lifting. (Although it took many iterations to get to code only using things that come with Gramps⌠like Gtk toolkit and importing only from already installed modules.)
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class JsonToCsvConverter(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="JSON to CSV Converter")
self.set_border_width(10)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(vbox)
self.input_button = Gtk.Button(label="Select Input JSON")
self.input_button.connect("clicked", self.on_input_clicked)
vbox.pack_start(self.input_button, True, True, 0)
self.output_button = Gtk.Button(label="Select Output CSV")
self.output_button.connect("clicked", self.on_output_clicked)
vbox.pack_start(self.output_button, True, True, 0)
self.convert_button = Gtk.Button(label="Convert")
self.convert_button.connect("clicked", self.on_convert_clicked)
vbox.pack_start(self.convert_button, True, True, 0)
self.input_file = None
self.output_file = None
def on_input_clicked(self, widget):
dialog = Gtk.FileChooserDialog(
title="Select Input JSON File",
parent=self,
action=Gtk.FileChooserAction.OPEN
)
dialog.add_buttons(
Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK
)
dialog.set_current_folder(sys.path[0])
response = dialog.run()
if response == Gtk.ResponseType.OK:
self.input_file = dialog.get_filename()
self.input_button.set_label(f"Input: {self.input_file.split('/')[-1]}")
dialog.destroy()
def on_output_clicked(self, widget):
dialog = Gtk.FileChooserDialog(
title="Select Output CSV File",
parent=self,
action=Gtk.FileChooserAction.SAVE
)
dialog.add_buttons(
Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.OK
)
dialog.set_current_folder(sys.path[0])
dialog.set_current_name("output.csv")
response = dialog.run()
if response == Gtk.ResponseType.OK:
self.output_file = dialog.get_filename()
if not self.output_file.endswith('.csv'):
self.output_file += '.csv'
self.output_button.set_label(f"Output: {self.output_file.split('/')[-1]}")
dialog.destroy()
def on_convert_clicked(self, widget):
if not self.input_file or not self.output_file:
dialog = Gtk.MessageDialog(
transient_for=self,
flags=0,
message_type=Gtk.MessageType.ERROR,
buttons=Gtk.ButtonsType.OK,
text="Please select both input and output files."
)
dialog.run()
dialog.destroy()
return
import json
import csv
from collections import OrderedDict
try:
with open(self.input_file, 'r') as json_file:
data = json.load(json_file)
fieldnames = set()
for item in data:
fieldnames.update(item.keys())
fieldnames = list(fieldnames)
with open(self.output_file, 'w', newline='') as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
writer.writeheader()
for row in data:
writer.writerow(OrderedDict((k, row.get(k, '')) for k in fieldnames))
dialog = Gtk.MessageDialog(
transient_for=self,
flags=0,
message_type=Gtk.MessageType.INFO,
buttons=Gtk.ButtonsType.OK,
text="Conversion completed successfully."
)
dialog.run()
dialog.destroy()
except Exception as e:
dialog = Gtk.MessageDialog(
transient_for=self,
flags=0,
message_type=Gtk.MessageType.ERROR,
buttons=Gtk.ButtonsType.OK,
text=f"An error occurred: {str(e)}\nError type: {type(e)}"
)
dialog.run()
dialog.destroy()
win = JsonToCsvConverter()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()