summaryrefslogtreecommitdiffstats
path: root/lib/silfont/scripts/psfsetglyphdata.py
blob: 9aa21628e50aa85be7de466e1bf8caec45f4ca40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python
__doc__ = '''Update and/or sort glyph_data.csv based on input file(s)'''
__url__ = 'http://github.com/silnrsi/pysilfont'
__copyright__ = 'Copyright (c) 2021 SIL International  (http://www.sil.org)'
__license__ = 'Released under the MIT License (http://opensource.org/licenses/MIT)'
__author__ = 'David Raymond'

from silfont.core import execute
import csv

argspec = [
    ('glyphdata', {'help': 'glyph_data csv file to update'}, {'type': 'incsv', 'def': 'glyph_data.csv'}),
    ('outglyphdata', {'help': 'Alternative output file name', 'nargs': '?'}, {'type': 'filename', 'def': None}),
    ('-a','--addcsv',{'help': 'Records to add to glyphdata'}, {'type': 'incsv', 'def': None}),
    ('-d', '--deletions', {'help': 'Records to delete from glyphdata'}, {'type': 'incsv', 'def': None}),
    ('-s', '--sortheader', {'help': 'Column header to sort by'}, {}),
    ('--sortalpha', {'help': 'Use with sortheader to sort alphabetically not numerically', 'action': 'store_true', 'default': False}, {}),
    ('-f', '--force', {'help': 'When adding, if glyph exists, overwrite existing data', 'action': 'store_true', 'default': False}, {}),
    ('-l','--log',{'help': 'Log file name'}, {'type': 'outfile', 'def': 'setglyphdata.log'}),
    ]

def doit(args):
    logger = args.logger
    gdcsv = args.glyphdata
    addcsv = args.addcsv
    dellist = args.deletions
    sortheader = args.sortheader
    force = args.force

    # Check arguments are valid
    if not(addcsv or dellist or sortheader): logger.log("At least one of -a, -d or -s must be specified", "S")
    if force and not addcsv: logger.log("-f should only be used with -a", "S")

    #
    # Process the glyph_data.csv
    #

    # Process the headers line
    gdheaders = gdcsv.firstline
    if 'glyph_name' not in gdheaders: logger.log("No glyph_name header in glyph data csv", "S")
    gdcsv.numfields = len(gdheaders)
    gdheaders = {header: col for col, header in enumerate(gdheaders)} # Turn into dict of form header: column
    gdnamecol = gdheaders["glyph_name"]
    if sortheader and sortheader not in gdheaders:
        logger.log(sortheader + " not in glyph data headers", "S")
    next(gdcsv.reader, None)  # Skip first line with headers in

    # Read the data in
    logger.log("Reading in exisitng glyph data file", "P")
    gddata = {}
    gdorder = []
    for line in gdcsv:
        gname = line[gdnamecol]
        gddata[gname] = line
        gdorder.append(gname)

    # Delete records from dellist

    if dellist:
        logger.log("Deleting items from glyph data based on deletions file", "P")
        dellist.numfields = 1
        for line in dellist:
            gname = line[0]
            if gname in gdorder:
                del gddata[gname]
                gdorder.remove(gname)
                logger.log(gname + " deleted from glyph data", "I")
            else:
                logger.log(gname + "not in glyph data", "W")

    #
    # Process the addcsv, if present
    #

    if addcsv:
        # Check if addcsv has headers; if not use gdheaders
        addheaders = addcsv.firstline
        headerssame = True
        if 'glyph_name' in addheaders:
            if addheaders != gdcsv.firstline: headerssame = False
            next(addcsv.reader)
        else:
            addheaders = gdheaders

        addcsv.numfields = len(addheaders)
        addheaders = {header: col for col, header in enumerate(addheaders)}  # Turn into dict of form header: column
        addnamecol = addheaders["glyph_name"]

        logger.log("Adding new records from add csv file", "P")
        for line in addcsv:
            gname = line[addnamecol]
            logtype = "added to"
            if gname in gdorder:
                if force: # Remove existing line
                    logtype = "replaced in"
                    del gddata[gname]
                    gdorder.remove(gname)
                else:
                    logger.log(gname + " already in glyphdata so new data not added", "W")
                    continue
            logger.log(f'{gname} {logtype} glyphdata', "I")

            if not headerssame: # need to construct new line based on addheaders
                newline = []
                for header in gdheaders:
                    val = line[addheaders[header]] if header in addheaders else ""
                    newline.append(val)
                line = newline

            gddata[gname] = line
            gdorder.append(gname)

    # Finally sort the data if sortheader supplied
    def numeric(x):
        try:
            numx = float(x)
        except ValueError:
            logger.log(f'Non-numeric value "{x}" in sort column; 0 used for sorting', "E")
            numx = 0
        return numx

    if sortheader:
        sortheaderpos = gdheaders[sortheader]
        if args.sortalpha:
            gdorder = sorted(gdorder, key=lambda x: gddata[x][sortheaderpos])
        else:
            gdorder = sorted(gdorder, key=lambda x: numeric(gddata[x][sortheaderpos]))

    # Now write the data out
    outfile = args.outglyphdata
    if not outfile:
        gdcsv.file.close()
        outfile = gdcsv.filename
    logger.log(f'Writing glyph data out to {outfile}', "P")
    with open(outfile, "w", newline="") as f:
        writer = csv.writer(f)
        writer.writerow(gdcsv.firstline)
        for glyphn in gdorder:
            writer.writerow(gddata[glyphn])

def cmd() : execute("",doit,argspec)
if __name__ == "__main__": cmd()