Workaround for Python 3 bug in ufo2ft which caused invalid OTF files to be generated. Closes #110

This commit is contained in:
Rasmus Andersson 2019-01-03 15:10:08 -08:00
parent d16ca04eaa
commit 799472b3f4
7 changed files with 270 additions and 77 deletions

109
Makefile
View file

@ -96,28 +96,72 @@ all_ufo_masters = $(Thin_ufo_d) \
$(FONTDIR)/var/%.var.ttf: src/%.designspace $(all_ufo_masters) $(FONTDIR)/var/%.var.ttf: src/%.designspace $(all_ufo_masters)
misc/fontbuild compile-var -o $@ $< misc/fontbuild compile-var -o $@ $<
$(FONTDIR)/const/Inter-UI-Thin.%: src/Inter-UI.designspace $(Thin_ufo_d)
# ---------- begin workaround for issue #110 -----------
# $(FONTDIR)/const/Inter-UI-Thin.%: src/Inter-UI.designspace $(Thin_ufo_d)
# misc/fontbuild compile -o $@ src/Inter-UI-Thin.ufo
# $(FONTDIR)/const/Inter-UI-ThinItalic.%: src/Inter-UI.designspace $(ThinItalic_ufo_d)
# misc/fontbuild compile -o $@ src/Inter-UI-ThinItalic.ufo
# $(FONTDIR)/const/Inter-UI-Regular.%: src/Inter-UI.designspace $(Regular_ufo_d)
# misc/fontbuild compile -o $@ src/Inter-UI-Regular.ufo
# $(FONTDIR)/const/Inter-UI-Italic.%: src/Inter-UI.designspace $(Italic_ufo_d)
# misc/fontbuild compile -o $@ src/Inter-UI-Italic.ufo
# $(FONTDIR)/const/Inter-UI-Black.%: src/Inter-UI.designspace $(Black_ufo_d)
# misc/fontbuild compile -o $@ src/Inter-UI-Black.ufo
# $(FONTDIR)/const/Inter-UI-BlackItalic.%: src/Inter-UI.designspace $(BlackItalic_ufo_d)
# misc/fontbuild compile -o $@ src/Inter-UI-BlackItalic.ufo
$(FONTDIR)/const/Inter-UI-Thin.ttf: src/Inter-UI.designspace $(Thin_ufo_d)
misc/fontbuild compile -o $@ src/Inter-UI-Thin.ufo misc/fontbuild compile -o $@ src/Inter-UI-Thin.ufo
$(FONTDIR)/const/Inter-UI-ThinItalic.%: src/Inter-UI.designspace $(ThinItalic_ufo_d) $(FONTDIR)/const/Inter-UI-ThinItalic.ttf: src/Inter-UI.designspace $(ThinItalic_ufo_d)
misc/fontbuild compile -o $@ src/Inter-UI-ThinItalic.ufo misc/fontbuild compile -o $@ src/Inter-UI-ThinItalic.ufo
$(FONTDIR)/const/Inter-UI-Regular.%: src/Inter-UI.designspace $(Regular_ufo_d) $(FONTDIR)/const/Inter-UI-Regular.ttf: src/Inter-UI.designspace $(Regular_ufo_d)
misc/fontbuild compile -o $@ src/Inter-UI-Regular.ufo misc/fontbuild compile -o $@ src/Inter-UI-Regular.ufo
$(FONTDIR)/const/Inter-UI-Italic.%: src/Inter-UI.designspace $(Italic_ufo_d) $(FONTDIR)/const/Inter-UI-Italic.ttf: src/Inter-UI.designspace $(Italic_ufo_d)
misc/fontbuild compile -o $@ src/Inter-UI-Italic.ufo misc/fontbuild compile -o $@ src/Inter-UI-Italic.ufo
$(FONTDIR)/const/Inter-UI-Black.%: src/Inter-UI.designspace $(Black_ufo_d) $(FONTDIR)/const/Inter-UI-Black.ttf: src/Inter-UI.designspace $(Black_ufo_d)
misc/fontbuild compile -o $@ src/Inter-UI-Black.ufo misc/fontbuild compile -o $@ src/Inter-UI-Black.ufo
$(FONTDIR)/const/Inter-UI-BlackItalic.%: src/Inter-UI.designspace $(BlackItalic_ufo_d) $(FONTDIR)/const/Inter-UI-BlackItalic.ttf: src/Inter-UI.designspace $(BlackItalic_ufo_d)
misc/fontbuild compile -o $@ src/Inter-UI-BlackItalic.ufo misc/fontbuild compile -o $@ src/Inter-UI-BlackItalic.ufo
$(FONTDIR)/const/Inter-UI-Thin.otf: src/Inter-UI.designspace $(Thin_ufo_d)
misc/fontbuild2 compile -o $@ src/Inter-UI-Thin.ufo
$(FONTDIR)/const/Inter-UI-ThinItalic.otf: src/Inter-UI.designspace $(ThinItalic_ufo_d)
misc/fontbuild2 compile -o $@ src/Inter-UI-ThinItalic.ufo
$(FONTDIR)/const/Inter-UI-Regular.otf: src/Inter-UI.designspace $(Regular_ufo_d)
misc/fontbuild2 compile -o $@ src/Inter-UI-Regular.ufo
$(FONTDIR)/const/Inter-UI-Italic.otf: src/Inter-UI.designspace $(Italic_ufo_d)
misc/fontbuild2 compile -o $@ src/Inter-UI-Italic.ufo
$(FONTDIR)/const/Inter-UI-Black.otf: src/Inter-UI.designspace $(Black_ufo_d)
misc/fontbuild2 compile -o $@ src/Inter-UI-Black.ufo
$(FONTDIR)/const/Inter-UI-BlackItalic.otf: src/Inter-UI.designspace $(BlackItalic_ufo_d)
misc/fontbuild2 compile -o $@ src/Inter-UI-BlackItalic.ufo
# ---------- end workaround for issue #110 -----------
# Instance UFO -> OTF, TTF # Instance UFO -> OTF, TTF
$(FONTDIR)/const/Inter-UI-%.otf: build/ufo/Inter-UI-%.ufo $(FONTDIR)/const/Inter-UI-%.otf: build/ufo/Inter-UI-%.ufo
misc/fontbuild compile -o $@ $< misc/fontbuild2 compile -o $@ $<
$(FONTDIR)/const/Inter-UI-%.ttf: build/ufo/Inter-UI-%.ufo $(FONTDIR)/const/Inter-UI-%.ttf: build/ufo/Inter-UI-%.ufo
misc/fontbuild compile -o $@ $< misc/fontbuild compile -o $@ $<
@ -152,23 +196,53 @@ build/ufo/Inter-UI-%.ufo: src/Inter-UI.designspace $(all_ufo_masters)
# hinted TTF files via autohint # hinted TTF files via autohint
$(FONTDIR)/const-hinted/%.ttf: $(FONTDIR)/const/%.ttf $(FONTDIR)/const-hinted/%.ttf: $(FONTDIR)/const/%.ttf
mkdir -p "$(dir $@)" mkdir -p "$(dir $@)"
ttfautohint --fallback-stem-width=256 --no-info --composites "$<" "$@" ttfautohint --fallback-stem-width=256 --no-info "$<" "$@"
# $(FONTDIR)/var-hinted/%.ttf: $(FONTDIR)/var/%.ttf # $(FONTDIR)/var-hinted/%.ttf: $(FONTDIR)/var/%.ttf
# mkdir -p "$(dir $@)" # mkdir -p "$(dir $@)"
# ttfautohint --fallback-stem-width=256 --no-info --composites "$<" "$@" # ttfautohint --fallback-stem-width=256 --no-info "$<" "$@"
# make sure intermediate TTFs are not gc'd by make # make sure intermediate TTFs are not gc'd by make
.PRECIOUS: $(FONTDIR)/const/%.ttf $(FONTDIR)/const-hinted/%.ttf $(FONTDIR)/var/%.var.ttf .PRECIOUS: $(FONTDIR)/const/%.ttf $(FONTDIR)/const-hinted/%.ttf $(FONTDIR)/var/%.var.ttf
# check var # check var
all_check_var: $(FONTDIR)/var/Inter-UI.var.ttf all_check_var: $(FONTDIR)/var/Inter-UI.var.ttf
misc/fontbuild checkfont $^ misc/fontbuild checkfont $(FONTDIR)/var/*.*
# test runs all tests # test runs all tests
# Note: all_check_const is generated by init.sh and runs "fontbuild checkfont" # Note: all_check_const is generated by init.sh and runs "fontbuild checkfont"
# on all otf and ttf files. # on all otf and ttf files.
test: all_check_const all_check_var test: all_check_const all_check_var
@echo "test: all ok"
# check does the same thing as test, but without any dependency checks, meaning
# it will check whatever font files are already built.
check:
misc/fontbuild checkfont $(FONTDIR)/const/*.* $(FONTDIR)/var/*.*
@echo "check: all ok"
.PHONY: test check
# samples renders PDF and PNG samples
samples: $(FONTDIR)/samples all_samples_pdf all_samples_png
$(FONTDIR)/samples/%.pdf: $(FONTDIR)/const/%.otf
misc/tools/fontsample/fontsample -o "$@" "$<"
$(FONTDIR)/samples/%.png: $(FONTDIR)/const/%.otf
misc/tools/fontsample/fontsample -o "$@" "$<"
$(FONTDIR)/samples:
mkdir -p $@
# load version, used by zip and dist # load version, used by zip and dist
VERSION := $(shell cat version.txt) VERSION := $(shell cat version.txt)
@ -223,8 +297,14 @@ build/release/Inter-UI-%.zip: build/tmp/a.zip
@echo write "$@" @echo write "$@"
@sh -c "if [ -f /usr/bin/open ]; then /usr/bin/open --reveal '$@'; fi" @sh -c "if [ -f /usr/bin/open ]; then /usr/bin/open --reveal '$@'; fi"
zip: ${ZIP_FILE_DEV} zip: all
zip_dist: pre_dist test ${ZIP_FILE_DIST} $(MAKE) check
$(MAKE) ${ZIP_FILE_DEV}
zip_dist: pre_dist all
$(MAKE) check
$(MAKE) ${ZIP_FILE_DIST}
.PHONY: zip zip_dist .PHONY: zip zip_dist
# distribution # distribution
@ -235,7 +315,8 @@ pre_dist:
exit 1; \ exit 1; \
fi fi
dist: zip_dist docs dist: zip_dist
$(MAKE) -j docs
misc/tools/versionize-css.py misc/tools/versionize-css.py
@echo "——————————————————————————————————————————————————————————————————" @echo "——————————————————————————————————————————————————————————————————"
@echo "" @echo ""
@ -309,4 +390,4 @@ install: install_otf
clean: clean:
rm -rvf build/tmp build/fonts rm -rvf build/tmp build/fonts
.PHONY: all web clean install install_otf install_ttf deploy pre_dist dist geninfo test glyphsync .PHONY: all web clean install install_otf install_ttf deploy pre_dist dist geninfo glyphsync

98
init.sh
View file

@ -41,7 +41,8 @@ else
clean=true clean=true
fi fi
# ————————————————————————————————————————————————————————————————————————————————————————————————
# ——————————————————————————————————————————————————————————————————
# virtualenv # virtualenv
mkdir -p "$VENV_DIR" mkdir -p "$VENV_DIR"
@ -57,7 +58,7 @@ else
fi fi
require_virtualenv() { require_virtualenv() {
# find pip # find pip3 (Python 3)
export pip=$(which pip3) export pip=$(which pip3)
if [ "$pip" = "" ]; then if [ "$pip" = "" ]; then
export pip=$(which pip) export pip=$(which pip)
@ -107,20 +108,53 @@ else
done done
fi fi
source "$VENV_DIR/bin/activate" # --------------------
# ISSUE #110 (bug in ufo2ft) requires Python 2 for OTF CFF compilation
UPDATE_TIMESTAMP_FILE="$VENV_DIR/last-pip-run.mark" # See also: https://github.com/googlei18n/ufo2ft/issues/306
REQUIREMENTS_FILE=$SRCDIR/requirements.txt PYTHON2=
PY_REQUIREMENTS_CHANGED=false if (which python2 >/dev/null); then
PYTHON2=$(which python2)
if [ "$REQUIREMENTS_FILE" -nt "$UPDATE_TIMESTAMP_FILE" ]; then elif (which python >/dev/null) && (python --version | grep -q 'ython 2'); then
echo "pip install -r $REQUIREMENTS_FILE" PYTHON2=$(which python)
pip install -r "$REQUIREMENTS_FILE" else
date '+%s' > "$UPDATE_TIMESTAMP_FILE" echo "Unable to find Python 2 (tried python2 and python)." >&2
PY_REQUIREMENTS_CHANGED=true echo "Python 2 is required to compile OTF files because of a Python-3 bug in a third-party library." >&2
exit 1
fi
# ln -svf "$PYTHON2" "$VENV_DIR/bin/python2"
VENV2_DIR=$BUILD_DIR/venv2
if [[ ! -d "$VENV2_DIR/bin" ]]; then
require_virtualenv
$virtualenv "--python=$PYTHON2" "$VENV2_DIR"
fi fi
# ———————————————————————————————————————————————————————————————————————————————————————————————— # ——————————————————————————————————————————————————————————————————
# check pip requirements
# primary env
REQUIREMENTS_FILE=$SRCDIR/requirements.txt
UPDATE_TIMESTAMP_FILE="$VENV_DIR/last-pip-run.mark"
if [ "$REQUIREMENTS_FILE" -nt "$UPDATE_TIMESTAMP_FILE" ]; then
echo "$VENV_DIR/bin/pip install -r $REQUIREMENTS_FILE"
"$VENV_DIR/bin/pip" install -r "$REQUIREMENTS_FILE"
date '+%s' > "$UPDATE_TIMESTAMP_FILE"
fi
# secondary env (Python 2)
REQUIREMENTS2_FILE=$SRCDIR/requirements2.txt
UPDATE_TIMESTAMP2_FILE="$VENV2_DIR/last-pip-run.mark"
if [ "$REQUIREMENTS2_FILE" -nt "$UPDATE_TIMESTAMP2_FILE" ]; then
echo "$VENV2_DIR/bin/pip install -r $REQUIREMENTS2_FILE"
"$VENV2_DIR/bin/pip" install -r "$REQUIREMENTS2_FILE"
date '+%s' > "$UPDATE_TIMESTAMP2_FILE"
fi
# ——————————————————————————————————————————————————————————————————
# active primary env (Python 3)
source "$VENV_DIR/bin/activate"
# ——————————————————————————————————————————————————————————————————
# deps # deps
DEPS_DIR=$BUILD_DIR/deps DEPS_DIR=$BUILD_DIR/deps
PATCH_DIR=$(pwd)/misc/patches PATCH_DIR=$(pwd)/misc/patches
@ -448,6 +482,20 @@ else
done done
echo "" >> "$GEN_MAKE_FILE" echo "" >> "$GEN_MAKE_FILE"
# all_samples_pdf target
echo -n "all_samples_pdf:" >> "$GEN_MAKE_FILE"
for style in "${all_styles[@]}"; do
echo -n " \$(FONTDIR)/samples/Inter-UI-${style}.pdf" >> "$GEN_MAKE_FILE"
done
echo "" >> "$GEN_MAKE_FILE"
# all_samples_png target
echo -n "all_samples_png:" >> "$GEN_MAKE_FILE"
for style in "${all_styles[@]}"; do
echo -n " \$(FONTDIR)/samples/Inter-UI-${style}.png" >> "$GEN_MAKE_FILE"
done
echo "" >> "$GEN_MAKE_FILE"
# all_const_fonts target # all_const_fonts target
# echo -n "all_const_fonts:" >> "$GEN_MAKE_FILE" # echo -n "all_const_fonts:" >> "$GEN_MAKE_FILE"
# for style in "${all_styles[@]}"; do # for style in "${all_styles[@]}"; do
@ -463,15 +511,15 @@ else
echo "" >> "$GEN_MAKE_FILE" echo "" >> "$GEN_MAKE_FILE"
fi fi
# ———————————————————————————————————————————————————————————————————————————————————————————————— # # ————————————————————————————————————————————————————————————————
# summary # # summary
if ! $VENV_ACTIVE; then # if ! $VENV_ACTIVE; then
echo -n "You can activate virtualenv by running " # echo -n "You can activate virtualenv by running "
if [ "$0" == "./init.sh" ]; then # if [ "$0" == "./init.sh" ]; then
# pretty format for common case # # pretty format for common case
echo '`source init.sh`' # echo '`source init.sh`'
else # else
echo "\`source \"$0\"\`" # echo "\`source \"$0\"\`"
fi # fi
fi # fi
fi fi

View file

@ -4,7 +4,7 @@ from __future__ import print_function, absolute_import
import sys, os import sys, os
from os.path import dirname, basename, abspath, relpath, join as pjoin from os.path import dirname, basename, abspath, relpath, join as pjoin
sys.path.append(abspath(pjoin(dirname(__file__), 'tools'))) sys.path.append(abspath(pjoin(dirname(__file__), 'tools')))
from common import BASEDIR, VENVDIR, getGitHash, getVersion from common import BASEDIR, VENVDIR, getGitHash, getVersion, execproc
import argparse import argparse
import datetime import datetime
@ -26,6 +26,7 @@ from glyphsLib.interpolation import apply_instance_data
from mutatorMath.ufo.document import DesignSpaceDocumentReader from mutatorMath.ufo.document import DesignSpaceDocumentReader
from multiprocessing import Process, Queue from multiprocessing import Process, Queue
from ufo2ft.filters.removeOverlaps import RemoveOverlapsFilter from ufo2ft.filters.removeOverlaps import RemoveOverlapsFilter
from ufo2ft import CFFOptimization
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
stripItalic_re = re.compile(r'(?:^|\b)italic(?:\b|$)', re.I | re.U) stripItalic_re = re.compile(r'(?:^|\b)italic(?:\b|$)', re.I | re.U)
@ -55,6 +56,7 @@ def fatal(msg):
sys.exit(1) sys.exit(1)
def composedGlyphIsNonTrivial(g, yAxisIsNonTrivial=False): def composedGlyphIsNonTrivial(g, yAxisIsNonTrivial=False):
# A non-trivial glyph is one that is composed from either multiple # A non-trivial glyph is one that is composed from either multiple
# components or that uses component transformations. # components or that uses component transformations.
@ -361,10 +363,10 @@ class Main(object):
args.srcfile, args.srcfile,
interpolate=False, interpolate=False,
masters_as_instances=False, masters_as_instances=False,
use_production_names=True,
round_instances=True, round_instances=True,
output_path=outfilename, output_path=outfilename,
output=['variable'], output=['variable'],
optimize_cff=True,
overlaps_backend='pathops', # use Skia's pathops overlaps_backend='pathops', # use Skia's pathops
) )
@ -426,21 +428,27 @@ class Main(object):
ufo = Font(args.srcfile) ufo = Font(args.srcfile)
updateFontVersion(ufo) updateFontVersion(ufo)
# if outfile is a ufo, simply move it to outfilename instead
# of running ots-sanitize.
output_path = tmpfilename
if formats[0] == 'ufo':
output_path = outfilename
# run fontmake to produce OTF/TTF file at tmpfilename # run fontmake to produce OTF/TTF file at tmpfilename
project.run_from_ufos( project.run_from_ufos(
[ ufo ], [ ufo ],
output_path=tmpfilename, output_path=output_path,
output=formats, output=formats,
optimize_cff=True, use_production_names=True,
optimize_cff=CFFOptimization.SUBROUTINIZE, # NONE
overlaps_backend='pathops', # use Skia's pathops overlaps_backend='pathops', # use Skia's pathops
remove_overlaps=True,
) )
# TODO: if outfile is a ufo, simply move it to outfilename instead if output_path == tmpfilename:
# of running ots-sanitize
# Run ots-sanitize on produced OTF/TTF file and write sanitized version # Run ots-sanitize on produced OTF/TTF file and write sanitized version
# to outfilename # to outfilename
self._ots_sanitize(tmpfilename, outfilename) self._ots_sanitize(output_path, outfilename)
def _ots_sanitize(self, tmpfilename, outfilename): def _ots_sanitize(self, tmpfilename, outfilename):
@ -592,7 +600,6 @@ class Main(object):
# patch and write UFO files # patch and write UFO files
# TODO: Only write out-of-date UFOs # TODO: Only write out-of-date UFOs
procs = [] procs = []
q = Queue()
for source in designspace.sources: for source in designspace.sources:
# source : fontTools.designspaceLib.SourceDescriptor # source : fontTools.designspaceLib.SourceDescriptor
# source.font : defcon.objects.font.Font # source.font : defcon.objects.font.Font
@ -737,23 +744,24 @@ class Main(object):
font.save() font.save()
def checkfont(self, fontfile, q):
def checkfont(self, fontfile): res, ok = execproc('ots-idempotent', fontfile)
try:
res = subprocess.check_output(
['ots-idempotent', fontfile],
shell=False
).strip()
# Note: ots-idempotent does not exit with an error in many cases where # Note: ots-idempotent does not exit with an error in many cases where
# it fails to sanitize the font. # it fails to sanitize the font, so we look at its output to determine
if str(res).find('Failed') != -1: # success or failure.
log.error('[checkfont] ots-idempotent failed for %r: %s' % ( if not ok or res.find('Failed') != -1:
fontfile, res)) log.error('%s: checkfont ots-idempotent: %s' % (fontfile, res))
return False q.put(False)
except: return
log.error('[checkfont] ots-idempotent failed for %r' % fontfile)
return False res, ok = execproc('ots-validator-checker', fontfile)
return True if not ok or res.find("didn't crash") == -1:
log.error('%s: checkfont ots-validator-checker: %s' % (fontfile, res))
q.put(False)
return
# ok
q.put(True)
def cmd_checkfont(self, argv): def cmd_checkfont(self, argv):
@ -765,16 +773,23 @@ class Main(object):
help='Font files') help='Font files')
args = argparser.parse_args(argv) args = argparser.parse_args(argv)
q = Queue()
if len(args.files) < 2:
self.checkfont(args.files[0], q)
else:
procs = []
for fontfile in args.files:
p = Process(target=self.checkfont, args=(fontfile, q))
p.start()
procs.append(p)
for p in procs:
p.join()
for fontfile in args.files: for fontfile in args.files:
if not self.checkfont(fontfile): if not q.get():
sys.exit(1) sys.exit(1)
# could use from multiprocessing import Pool
# p = Pool(8)
# p.map(self.checkfont, args.files)
# p.terminate()
if __name__ == '__main__': if __name__ == '__main__':
Main().main(sys.argv) Main().main(sys.argv)

6
misc/fontbuild2 Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
pushd "$(dirname "$0")/.." >/dev/null
SRCDIR=$(PWD)
popd >/dev/null
"$SRCDIR/build/venv2/bin/python" misc/fontbuild "$@"

View file

@ -10,6 +10,30 @@ BASEDIR = abspath(pjoin(dirname(__file__), os.pardir, os.pardir))
VENVDIR = pjoin(BASEDIR, 'build', 'venv') VENVDIR = pjoin(BASEDIR, 'build', 'venv')
sys.path.append(pjoin(VENVDIR, 'lib', 'python', 'site-packages')) sys.path.append(pjoin(VENVDIR, 'lib', 'python', 'site-packages'))
PYVER = sys.version_info[0]
_enc_kwargs = {}
if PYVER >= 3:
_enc_kwargs = {'encoding': 'utf-8'}
# Returns (output :str, success :bool)
def execproc(*args):
p = subprocess.run(
args,
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
**_enc_kwargs
)
return (p.stdout.strip(), p.returncode == 0)
def readTextFile(filename):
with open(filename, 'r', **_enc_kwargs) as f:
return f.read()
_gitHash = None _gitHash = None
def getGitHash(): def getGitHash():
@ -19,7 +43,8 @@ def getGitHash():
try: try:
_gitHash = subprocess.check_output( _gitHash = subprocess.check_output(
['git', '-C', BASEDIR, 'rev-parse', '--short', 'HEAD'], ['git', '-C', BASEDIR, 'rev-parse', '--short', 'HEAD'],
shell=False shell=False,
**_enc_kwargs
).strip() ).strip()
except: except:
pass pass
@ -30,8 +55,7 @@ _version = None
def getVersion(): def getVersion():
global _version global _version
if _version is None: if _version is None:
with open(pjoin(BASEDIR, 'version.txt'), 'r') as f: _version = readTextFile(pjoin(BASEDIR, 'version.txt')).strip()
_version = f.read().strip()
return _version return _version

View file

@ -1,7 +1,9 @@
glyphsLib==3.1.4
skia-pathops==0.2.0.post2 skia-pathops==0.2.0.post2
fontmake==1.8.0 fontmake==1.8.0
fs==2.2.0
# for fontTools/varLib/interpolatable.py # for fontTools/varLib/interpolatable.py
numpy==1.15.4 numpy==1.15.4
scipy==1.1.0 scipy==1.2.0
munkres==1.0.12 munkres==1.0.12

17
requirements2.txt Normal file
View file

@ -0,0 +1,17 @@
# for secondry env (Python 2)
# should match requirements.txt except from the "Python 2 specific" section.
glyphsLib==3.1.4
skia-pathops==0.2.0.post2
fontmake==1.8.0
fs==2.2.0
# for fontTools/varLib/interpolatable.py
numpy==1.15.4
scipy==1.2.0
munkres==1.0.12
# Python 2 specific
enum34==1.1.6
typing==3.6.6
backports.os==0.1.1