Skip to content

Commit b316a75

Browse files
committed
improve clarity when importing as module
1 parent 2dc5ad9 commit b316a75

File tree

1 file changed

+91
-77
lines changed

1 file changed

+91
-77
lines changed

goadbWriter.py

Lines changed: 91 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from defcon import Font, Glyph
1818

1919

20-
def check_input_file(parser, file_name):
20+
def _check_input_file(parser, file_name):
2121
fn = Path(file_name)
2222
if fn.suffix.lower() != '.ufo':
2323
parser.error(f'{fn.name} is not a UFO file')
@@ -26,7 +26,7 @@ def check_input_file(parser, file_name):
2626
return file_name
2727

2828

29-
def get_args(args=None):
29+
def _get_args(args=None):
3030
parser = argparse.ArgumentParser(
3131
description=__doc__,
3232
)
@@ -50,8 +50,8 @@ def get_args(args=None):
5050
)
5151

5252
parser.add_argument(
53-
'input_file',
54-
type=lambda f: check_input_file(parser, f),
53+
'input_ufo',
54+
type=lambda f: _check_input_file(parser, f),
5555
action='store',
5656
help='UFO file',
5757
)
@@ -173,20 +173,20 @@ def _make_agd_dict():
173173

174174
def get_glyph_order(f, include_template_glyphs=False):
175175
'''
176-
Figure out the glyph order.
177-
* make sure .notdef is first,
178-
* respect skipExportGlyphs,
179-
* include (un-filled) template glyphs if desired
176+
Figure out the glyph order of a UFO file.
177+
* make sure .notdef is first,
178+
* respect skipExportGlyphs,
179+
* include (un-filled) template glyphs if desired
180180
181181
In the case that the public.glyphOrder key does not exist, resort to
182182
unrefined sorting:
183-
* encoded: by code point
184-
* unencoded: following code point sorting (deduced by glyph name)
185-
* unencoded: alphabetically by name (for the rest)
183+
* encoded glyphs: by code point
184+
* unencoded glyphs: following code point sorting, deduced by glyph name
185+
* remaining unencoded glyphs: alphabetically by name (for the rest)
186186
187187
NB: defcon and RF have different ways of determining template glyphs.
188-
in defcon, f.glyphOrder includes template glyphs
189-
in RF, f.glyphOrder excludes them
188+
in defcon, `f.glyphOrder` includes template glyphs
189+
in RF, `f.glyphOrder` excludes them
190190
'''
191191

192192
glyph_order = f.glyphOrder
@@ -242,7 +242,7 @@ def get_glyph_order(f, include_template_glyphs=False):
242242
return order
243243

244244

245-
def make_uni_name(cp):
245+
def make_uni_gname(cp):
246246
'''
247247
convert codepoint to uniXXXX (or uXXXXX) glyph name
248248
'''
@@ -253,18 +253,18 @@ def make_uni_name(cp):
253253
return uni_name
254254

255255

256-
def make_uni_override(cp_list):
256+
def _make_uni_override(cp_list):
257257
'''
258258
comma-separated Unicode override string
259259
(or a single string if len(cp_list) == 1)
260260
'''
261-
unicode_override = ','.join([make_uni_name(cp) for cp in cp_list])
261+
unicode_override = ','.join([make_uni_gname(cp) for cp in cp_list])
262262
return unicode_override
263263

264264

265-
def make_unique_final_name(gname):
265+
def _make_unique_final_name(gname):
266266
'''
267-
Since final glyph names need to be sanitized, a duplication of final glyph
267+
Since final glyph names need to be sanitized, a duplication of
268268
names is possible. This adds a 4-digit index to the glyph name.
269269
270270
If the glyph name already has a 4-digit index, the index is incremented.
@@ -282,20 +282,20 @@ def make_unique_final_name(gname):
282282
return f'{gname_stem}{index:0>4}'
283283

284284

285-
def sanitize_final_name(gname):
285+
def sanitize_final_gname(gname):
286286
'''
287287
The following characters are allowed in friendly- but not final names:
288-
U+002A * asterisk
289-
U+002B + plus sign
290-
U+002D - hyphen-minus
291-
U+003A : colon
292-
U+005E ^ circumflex accent
293-
U+007C | vertical bar
294-
U+007E ~ tilde
288+
U+002A * asterisk
289+
U+002B + plus sign
290+
U+002D - hyphen-minus
291+
U+003A : colon
292+
U+005E ^ circumflex accent
293+
U+007C | vertical bar
294+
U+007E ~ tilde
295295
296296
In addition to that, final glyph names
297-
* may not start with a period
298-
* may not start with a digit
297+
* may not start with a period
298+
* may not start with a digit
299299
300300
see also
301301
https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#2fi-glyph-name
@@ -330,12 +330,27 @@ def sanitize_final_name(gname):
330330
return gname
331331

332332

333+
def _dummy_glyph(f, gname):
334+
'''
335+
make sure a glyph object is present -- no matter if it exists in the UFO
336+
or not.
337+
'''
338+
try:
339+
# glyph exists in the UFO
340+
glyph = f[gname]
341+
except KeyError:
342+
# template glyph
343+
glyph = Glyph()
344+
glyph.name = gname
345+
return glyph
346+
347+
333348
class GlyphBaptism(object):
334349
'''
335350
Simple deduction of final glyph name.
336-
Not dealing with ligatures/alternates here.
351+
(Deliberately ignoring ligatures and alternates here.)
337352
338-
Either
353+
Considering either one of the following scenarios:
339354
- glyph name is in the AGD dict, makeotf associates the code point
340355
- glyph name is not in the AGD, but the glyph has attached code point(s)
341356
- glyph name implies a code point (uniXXXX or uXXXXX)
@@ -356,7 +371,7 @@ def __init__(self, gn_friendly, g=None, gn_final=None, cp_override=None):
356371
# this is the normal expectation for most glyphs
357372
if self.gn_final is None:
358373
self.assign_final_and_cp_override()
359-
self.gn_final = sanitize_final_name(self.gn_final)
374+
self.gn_final = sanitize_final_gname(self.gn_final)
360375

361376
# in other cases (alternates/ligatures), we generate the final name
362377
# outside, and use this object for data storage only.
@@ -382,7 +397,7 @@ def assign_final_and_cp_override(self):
382397
# glyph name is in AGD, but multiple code points attached;
383398
# override is needed
384399
self.gn_final = self.gn_friendly
385-
self.cp_override = make_uni_override(self.glyph.unicodes)
400+
self.cp_override = _make_uni_override(self.glyph.unicodes)
386401
else:
387402
# just one codepoint
388403
expected_codepoint = agd_cp
@@ -392,7 +407,7 @@ def assign_final_and_cp_override(self):
392407
self.gn_final = agd_final
393408
else:
394409
# codepoint is different from what we expect
395-
self.gn_final = make_uni_name(self.glyph.unicode)
410+
self.gn_final = make_uni_gname(self.glyph.unicode)
396411

397412
# glyph name implies Unicode value (uniXXXX or uXXXXX)
398413
elif uni_name_match:
@@ -403,8 +418,8 @@ def assign_final_and_cp_override(self):
403418
# no codepoint assigned to glyph, codepoint will be assigned
404419
# through the glyph name only
405420
# The glyph name could be uniFFFFF, which is not a legal final
406-
# name, so we are sending it through make_uni_name.
407-
self.gn_final = make_uni_name(cp_int)
421+
# name, so we are sending it through make_uni_gname.
422+
self.gn_final = make_uni_gname(cp_int)
408423
elif len(self.glyph.unicodes) > 1:
409424
# glyph name implies one code point, but multiple code points
410425
# are attached -- override needed.
@@ -415,18 +430,18 @@ def assign_final_and_cp_override(self):
415430
# The final name does not matter, because it is
416431
# overridden anyway.
417432
self.gn_final = self.gn_friendly
418-
self.cp_override = make_uni_override(self.glyph.unicodes)
433+
self.cp_override = _make_uni_override(self.glyph.unicodes)
419434
else:
420435
# just one codepoint
421436
actual_codepoint = self.glyph.unicode
422437
if cp_int == actual_codepoint:
423438
# codepoint is the expected one. Name could be uniFFFFF,
424439
# which makeotf only understands as uFFFFF.
425-
self.gn_final = make_uni_name(cp_int)
440+
self.gn_final = make_uni_gname(cp_int)
426441
else:
427442
# codepoint is different from what the name implies
428443
# (weird flex but OK)
429-
self.gn_final = make_uni_name(self.glyph.unicode)
444+
self.gn_final = make_uni_gname(self.glyph.unicode)
430445

431446
# custom glyph name
432447
else:
@@ -436,41 +451,26 @@ def assign_final_and_cp_override(self):
436451
elif len(self.glyph.unicodes) > 1:
437452
# multiple code points are attached -- override needed
438453
self.gn_final = self.gn_friendly
439-
self.cp_override = make_uni_override(self.glyph.unicodes)
454+
self.cp_override = _make_uni_override(self.glyph.unicodes)
440455
else:
441456
# just one codepoint, the final name will tell makeotf about it
442-
self.gn_final = make_uni_name(self.glyph.unicode)
457+
self.gn_final = make_uni_gname(self.glyph.unicode)
443458

444459

445-
def fill_gn_dict(gb, glyph_name_dict):
460+
def _fill_gn_dict(gb, glyph_name_dict):
446461
'''
447462
This slightly awkward method of adding values to a dictionary ensures that
448463
the final glyph name is unique.
449464
'''
450465
final_name = gb.gn_final
451466
while final_name in [gb.gn_final for gb in glyph_name_dict.values()]:
452-
final_name = make_unique_final_name(final_name)
467+
final_name = _make_unique_final_name(final_name)
453468
gb.gn_final = final_name
454469
glyph_name_dict[gb.gn_friendly] = gb
455470
return glyph_name_dict
456471

457472

458-
def get_glyph(f, gname):
459-
'''
460-
make sure a glyph object is present -- no matter if it exists in the UFO
461-
or not.
462-
'''
463-
try:
464-
# glyph exists in the UFO
465-
glyph = f[gname]
466-
except KeyError:
467-
# template glyph
468-
glyph = Glyph()
469-
glyph.name = gname
470-
return glyph
471-
472-
473-
def make_glyph_name_dict(f, glyph_order):
473+
def _make_glyph_name_dict(f, glyph_order):
474474
'''
475475
make a dictionary:
476476
{friendly name: gb object}
@@ -503,12 +503,12 @@ def make_glyph_name_dict(f, glyph_order):
503503
liga_glyphs = [gn for gn in glyph_order if '_' in gn]
504504

505505
for gn in base_glyphs:
506-
g = get_glyph(f, gn)
506+
g = _dummy_glyph(f, gn)
507507
gb = GlyphBaptism(g.name, g)
508-
glyph_name_dict = fill_gn_dict(gb, glyph_name_dict)
508+
glyph_name_dict = _fill_gn_dict(gb, glyph_name_dict)
509509

510510
for gn in alt_glyphs:
511-
g = get_glyph(f, gn)
511+
g = _dummy_glyph(f, gn)
512512
stem, suffixes = g.name.split('.', 1)
513513
if stem in glyph_name_dict:
514514
final_name_stem = glyph_name_dict.get(stem).gn_final
@@ -521,12 +521,12 @@ def make_glyph_name_dict(f, glyph_order):
521521

522522
if g.unicodes:
523523
# the alt glyph itself may have a codepoint
524-
gb.cp_override = make_uni_override(g.unicodes)
524+
gb.cp_override = _make_uni_override(g.unicodes)
525525

526-
glyph_name_dict = fill_gn_dict(gb, glyph_name_dict)
526+
glyph_name_dict = _fill_gn_dict(gb, glyph_name_dict)
527527

528528
for gn in liga_glyphs:
529-
g = get_glyph(f, gn)
529+
g = _dummy_glyph(f, gn)
530530
liga_chunks = g.name.split('_')
531531
liga_chunks_final = []
532532
for chunk in liga_chunks:
@@ -542,14 +542,14 @@ def make_glyph_name_dict(f, glyph_order):
542542

543543
if g.unicodes:
544544
# some ligatures have codepoints
545-
gb.cp_override = make_uni_override(g.unicodes)
545+
gb.cp_override = _make_uni_override(g.unicodes)
546546

547-
glyph_name_dict = fill_gn_dict(gb, glyph_name_dict)
547+
glyph_name_dict = _fill_gn_dict(gb, glyph_name_dict)
548548

549549
return glyph_name_dict
550550

551551

552-
def build_goadb(glyph_order, glyph_name_dict):
552+
def _make_goadb_content(glyph_order, glyph_name_dict):
553553
goadb = []
554554
for gname in glyph_order:
555555
gb = glyph_name_dict.get(gname)
@@ -560,22 +560,36 @@ def build_goadb(glyph_order, glyph_name_dict):
560560
return '\n'.join(goadb)
561561

562562

563-
def main(test_args=None):
564-
args = get_args(test_args)
565-
f = Font(args.input_file)
566-
glyph_order = get_glyph_order(f, args.template)
567-
glyph_name_dict = make_glyph_name_dict(f, glyph_order)
568-
goadb = build_goadb(glyph_order, glyph_name_dict)
569-
output_path = args.output
563+
def make_goadb(input_ufo, include_template_glyphs=False):
564+
'''
565+
Make a GOADB from an input UFO.
566+
Optionally, template glyphs can be included.
567+
'''
568+
f = Font(input_ufo)
569+
glyph_order = get_glyph_order(f, include_template_glyphs)
570+
glyph_name_dict = _make_glyph_name_dict(f, glyph_order)
571+
goadb_content = _make_goadb_content(glyph_order, glyph_name_dict)
572+
return goadb_content
570573

574+
575+
def write_goadb(goadb_content, output_path=None):
576+
'''
577+
Write the GOADB to an output file or folder.
578+
'''
571579
if output_path and output_path.is_file():
572580
with open(output_path, 'w') as blob:
573-
blob.write(goadb + '\n')
581+
blob.write(goadb_content + '\n')
574582
elif output_path and output_path.is_dir():
575583
with open(output_path / 'GlyphOrderAndAliasDB', 'w') as blob:
576-
blob.write(goadb + '\n')
584+
blob.write(goadb_content + '\n')
577585
else:
578-
print(goadb)
586+
print(goadb_content)
587+
588+
589+
def main(test_args=None):
590+
args = _get_args(test_args)
591+
goadb_content = make_goadb(args.input_ufo, args.template)
592+
write_goadb(goadb_content, args.output_path)
579593

580594

581595
if __name__ == '__main__':

0 commit comments

Comments
 (0)