Skip to content

Commit 8415357

Browse files
authored
Merge pull request #1163 from googlefonts/tag-lift
add_tags: added
2 parents aef42ac + 1dad773 commit 8415357

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

Lib/gftools/scripts/add_tags.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Add and replace tags from another tagging spreadsheet.
4+
"""
5+
import csv
6+
import argparse
7+
from pathlib import Path
8+
9+
10+
def read_csv(filepath):
11+
"""Read CSV file and return list of rows."""
12+
with open(filepath, "r", encoding="utf-8") as f:
13+
reader = csv.reader(f)
14+
return list(reader)
15+
16+
17+
def write_csv(filepath, rows):
18+
"""Write rows to CSV file."""
19+
with open(filepath, "w", encoding="utf-8", newline="") as f:
20+
writer = csv.writer(f, lineterminator="\n")
21+
writer.writerows(rows)
22+
23+
24+
def sort_rows(rows):
25+
"""
26+
Sort rows by displayName (col 0) and category (col 1).
27+
Ported from JS code:
28+
if (`${a.displayName},${a.category}` < `${b.displayName},${b.category}`)
29+
"""
30+
31+
data_rows = rows
32+
33+
def sort_key(row):
34+
# Create sort key as "displayName,category"
35+
return f"{row[0]},{row[1]},{row[2]}"
36+
37+
sorted_data = sorted(data_rows, key=sort_key)
38+
return sorted_data
39+
40+
41+
def merge_csvs(source_path, target_path, tag_category, output_path=None):
42+
"""
43+
Merge source CSV into target CSV.
44+
- If first 3 columns match, update 4th column only
45+
- Otherwise, add new row
46+
- Sort and save result
47+
"""
48+
source_rows = read_csv(source_path)
49+
target_rows = read_csv(target_path)
50+
51+
# Assume first row is header
52+
if len(source_rows) == 0 or len(target_rows) == 0:
53+
print("Error: One or both CSV files are empty")
54+
return
55+
56+
source_data = {(r[0], r[1], r[2]): r for r in source_rows}
57+
target_data = {(r[0], r[1], r[2]): r for r in target_rows if r}
58+
59+
to_add = set(source_data.keys()) - set(target_data.keys())
60+
to_update = set(source_data.keys()) & set(target_data.keys())
61+
62+
for key in to_add:
63+
_, _, category = key
64+
if category != tag_category:
65+
continue
66+
target_data[key] = source_data[key]
67+
68+
for key in to_update:
69+
_, _, category = key
70+
if category != tag_category:
71+
continue
72+
target_data[key][3] = source_data[key][3]
73+
74+
all_rows = list(target_data.values())
75+
sorted_rows = sort_rows(all_rows)
76+
77+
output = output_path if output_path else target_path
78+
write_csv(output, sorted_rows)
79+
print(f"Merged CSV saved to: {output}")
80+
print(f"Total rows (including header): {len(sorted_rows)}")
81+
82+
83+
def main(args=None):
84+
parser = argparse.ArgumentParser(
85+
description="Merge two CSV files with custom logic and sorting"
86+
)
87+
parser.add_argument(
88+
"source", type=Path, help="Source CSV file (rows to merge from)"
89+
)
90+
parser.add_argument(
91+
"target", type=Path, help="Target CSV file (rows to merge into)"
92+
)
93+
parser.add_argument("tag_category", help="Tag category to add/replace")
94+
parser.add_argument(
95+
"-o", "--output", type=Path, help="Output CSV file (default: overwrite target)"
96+
)
97+
args = parser.parse_args(args)
98+
99+
merge_csvs(args.source, args.target, args.tag_category, args.output)
100+
101+
102+
if __name__ == "__main__":
103+
main()

0 commit comments

Comments
 (0)