# This file is part of Beremiz Runtime
# Copyright (C) 2013: Laurent BESSARD
# Copyright (C) 2017: Andrey Skvortsov
# Copyright (C) 2025: Edouard Tisserant
# See COPYING file for copyrights details.
from collections import OrderedDict
def __init__(self, *args):
def _CSV_int_Load(fname):
entry = csv_int_files.get(fname, None)
csvfile = open(fname, 'rb')
dialect = csv.Sniffer().sniff(csvfile.read(1024))
reader = csv.reader(csvfile, dialect)
entry = Entry(fname, dialect, data)
csv_int_files[fname] = entry
def _CSV_str_Load(fname):
entry = csv_str_files.get(fname, None)
csvfile = open(fname, 'rb')
dialect = csv.Sniffer().sniff(csvfile.read(1024))
reader = csv.reader(csvfile, dialect)
first_row = reader.__next__()
col_headers = OrderedDict([(name, index+1) for index, name
in enumerate(first_row[1:])])
max_row_len = len(first_row)
row_headers = OrderedDict()
for index, row in enumerate(reader):
row_headers[row[0]] = index+1
max_row_len = max(max_row_len, len(row))
entry = Entry(fname, dialect, col_headers, row_headers, max_row_len, data)
csv_str_files[fname] = entry
def _CSV_str_Create(fname):
data = [[]] # start with an empty row, acounting for header row
col_headers = OrderedDict()
row_headers = OrderedDict()
max_row_len = 1 # set to one initialy, accounting for header column
entry = Entry(fname, dialect, col_headers, row_headers, max_row_len, data)
csv_str_files[fname] = entry
def _CSV_Save_data(fname, dialect, data):
wfile = open(fname, 'wb')
writer = csv.writer(wfile) if not(dialect) else csv.writer(wfile, dialect)
def _CSV_int_Save(entry):
fname, dialect, data = entry()
_CSV_Save_data(fname, dialect, data)
def _CSV_str_Save(entry):
fname, dialect, col_headers, row_headers, max_row_len, data = entry()
_CSV_Save_data(fname, dialect, data)
_already_registered_cb = False
def _CSV_OnIdle_callback():
global _already_registered_cb, cvs_int_changed, cvs_str_changed
_already_registered_cb = False
while len(cvs_int_changed):
entry = cvs_int_changed.pop()
while len(cvs_str_changed):
entry = cvs_str_changed.pop()
def _CSV_register_OnIdle_callback():
global _already_registered_cb
if not _already_registered_cb:
OnIdle.append(_CSV_OnIdle_callback)
_already_registered_cb = True
def _CSV_int_modified(entry):
cvs_int_changed.add(entry)
_CSV_register_OnIdle_callback()
def _CSV_str_modified(entry):
cvs_str_changed.add(entry)
_CSV_register_OnIdle_callback()
def CSVRdInt(fname, rowidx, colidx):
Return value at row/column pointed by integer indexes
Assumes data starts at first row and first column, no headers.
_fname, _dialect, data = _CSV_int_Load(fname)()
if not row and rowidx == len(data)-1:
def CSVRdStr(fname, rowname, colname):
Return value at row/column pointed by a pair of names as string
Assumes first row is column headers and first column is row name.
fname, dialect, col_headers, row_headers, max_row_len, data = _CSV_str_Load(fname)()
rowidx = row_headers[rowname]
colidx = col_headers[colname]
return data[rowidx][colidx]
def CSVWrInt(fname, rowidx, colidx, content):
Update value at row/column pointed by integer indexes
Assumes data starts at first row and first column, no headers.
entry = _CSV_int_Load(fname)
fname, dialect, data = entry()
if rowidx > 0 and colidx >= len(data[0]):
row.extend([""] * (colidx - len(row)) + [content])
def CSVWrStr(fname, rowname, colname, content):
Update value at row/column pointed by a pair of names as string.
Assumes first row is column headers and first column is row name.
entry = _CSV_str_Load(fname)
entry = _CSV_str_Create(fname)
fname, dialect, col_headers, row_headers, max_row_len, data = entry()
rowidx = row_headers[rowname]
# create a new row with appropriate header
row_headers[rowname] = rowidx
colidx = col_headers[colname]
# adjust col headers content
first_row += [""]*(max_row_len - len(first_row)) + [colname]
colidx = col_headers[colname] = max_row_len
max_row_len = max_row_len + 1
row += [""]*(colidx - len(row)) + [content]
global csv_int_files, csv_str_files, cvs_int_changed, cvs_str_changed
# Force saving modified CSV files