Below is an editable table UI along the lines of what Gregory was suggesting...
It uses a list of lists to create a simplified spreadsheet and allows you to edit each cell.
I would need more requirements to take it further:
Column headers or not?
Row headers or not?
Maximum column count?
Maximum row count?
Integers or floating point?
It would be cool if you could create a replacement for the default_list_of_lists() function that generates the kind of data you are interested in?
Why not just enter the data in a real spreadsheet (Apple Numbers, Google Sheets) and use Python csv to read in the data.
#!/usr/bin/env python
'''
Python script that reads in a json data file,
allows the user to edit it and then
save the results back to the data file.
'''
import bottle, json, platform, string, sys, time, webbrowser
print('Python app begins: {}'.format(time.ctime()))
data_file_name = __file__.rpartition('.')[0] + '.json'
def default_list_of_lists():
return [['{}{}'.format(r,c) for r in string.uppercase] for c in xrange(8)]
def read_data_file(in_file_name = data_file_name):
try:
with open(in_file_name) as in_file:
return json.load(in_file)
except IOError:
pass
return default_list_of_lists()
def write_data_file(in_data, in_file_name = data_file_name):
if in_data:
with open(in_file_name, 'w') as out_file:
json.dump(in_data, out_file)
table_fmt = '<table>\n{}\n</table>'
row_fmt = ' <tr>\n{}\n </tr>'
item_fmt = ' <td><div contenteditable>{}</td>'
def list_to_html_row(in_list):
if not isinstance(in_list, list):
return row_fmt.format(in_list)
return row_fmt.format('\n'.join([item_fmt.format(x) for x in in_list]))
def list_of_lists_to_html_table(in_list):
if not in_list:
return '<h3>No data.</h3>'
if not isinstance(in_list, list):
return in_list
return table_fmt.format('\n'.join([list_to_html_row(row_list)
for row_list in in_list]))
def get_footer():
def product_link(in_name, in_url, in_version):
return '<a href="http://{}">{} {}</a>'.format(in_url, in_name, in_version)
python_link = product_link('Python', 'python.org', platform.python_version())
bottle_link = product_link('Bottle', 'bottlepy.org', bottle.__version__)
fmt = '\n\n<p><p><sub>A webapp written in {} and {}.</sub>'
return fmt.format(python_link, bottle_link)
footer = get_footer()
app = bottle.Bottle(__name__)
@app.route('/')
def index():
#the_list = read_data_file()
header = '<h1>Python + Bottle webapp that allows you to edit a list of lists</h1>\n\n'
body = '''
<form action="/" method="post">
{}
<input value="Save to '{}'" type="submit" />
</form>
'''.format(list_of_lists_to_html_table(the_list),
data_file_name.rpartition('/')[2])
return header + body + footer
@app.post('/')
def save():
#print(bottle.request.forms.keys())
#return bottle.request.forms.keys()
return 'Save is not yet implemented.'
if __name__ == '__main__':
the_list = read_data_file()
write_data_file(the_list)
webbrowser.open('safari-http://127.0.0.1:8080')
#webbrowser.open('http://127.0.0.1:8080')
app.run(debug=True)
print('Python app ends: {}'.format(time.ctime()))