Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple UFOs at once #92

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 33 additions & 19 deletions src/ufonormalizer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from collections import OrderedDict
from io import open
import logging
import sys

try:
from ._version import __version__
Expand Down Expand Up @@ -46,7 +47,7 @@ def main(args=None):
parser = argparse.ArgumentParser(description=description)
parser.add_argument("input",
help="Path to a UFO to normalize.",
nargs="?")
nargs="+")
parser.add_argument("-t", "--test",
help="Run the normalizer's internal tests.",
action="store_true")
Expand Down Expand Up @@ -85,16 +86,17 @@ def main(args=None):
logLevel = "DEBUG" if args.verbose else "ERROR" if args.quiet else "INFO"
logging.basicConfig(level=logLevel, format="%(message)s")

if args.input is None:
parser.error("No input path was specified.")
inputPath = os.path.normpath(args.input)
outputPath = args.output
onlyModified = not args.all
if not os.path.exists(inputPath):
parser.error(f'Input path does not exist: "{ inputPath }".')
if os.path.splitext(inputPath)[-1].lower() != ".ufo":
parser.error(f'Input path is not a UFO: "{ inputPath }".')
if len(args.input) > 1 and args.output:
parser.error("can't use -o/--output with multiple input UFOs")
elif len(args.input) == 1:
inputPath = os.path.normpath(args.input[0])
inputPaths = [inputPath]
outputPaths = [args.output or inputPath]
else:
inputPaths = [os.path.normpath(inputPath) for inputPath in args.input]
outputPaths = inputPaths

onlyModified = not args.all
if args.float_precision >= 0:
floatPrecision = args.float_precision
elif args.float_precision == -1:
Expand All @@ -104,16 +106,28 @@ def main(args=None):

writeModTimes = not args.no_mod_times

allSkipped = True
message = 'Normalizing "%s".'
if not onlyModified:
message += " Processing all files."
log.info(message, os.path.basename(inputPath))
start = time.time()
normalizeUFO(inputPath, outputPath=outputPath, onlyModified=onlyModified,
floatPrecision=floatPrecision, writeModTimes=writeModTimes)
runtime = time.time() - start
log.info("Normalization complete (%.4f seconds).", runtime)

for inputPath, outputPath in zip(inputPaths, outputPaths):
if not os.path.exists(inputPath):
log.error(f'Skipping non-existent input path: "{ inputPath }".')
continue
if os.path.splitext(inputPath)[-1].lower() != ".ufo":
log.error(f'Skipping input path that isn\'t a UFO: "{ inputPath }".')
continue
allSkipped = False

if not onlyModified:
message += " Processing all files."
log.info(message, os.path.basename(inputPath))
start = time.time()
normalizeUFO(inputPath, outputPath=outputPath, onlyModified=onlyModified,
floatPrecision=floatPrecision, writeModTimes=writeModTimes)
runtime = time.time() - start
log.info("Normalization complete (%.4f seconds).", runtime)

if allSkipped:
sys.exit(2)

# ---------
# Internals
Expand Down
26 changes: 19 additions & 7 deletions tests/test_ufonormalizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from io import StringIO
from tempfile import TemporaryDirectory

import ufonormalizer

GLIFFORMAT1 = '''\
<?xml version="1.0" encoding="UTF-8"?>
<glyph name="period" format="1">
Expand Down Expand Up @@ -196,6 +198,11 @@ def __init__(self, methodName):
if not hasattr(self, "assertRaisesRegex"):
self.assertRaisesRegex = self.assertRaisesRegexp

def assertLogsContain(self, logsContext, phrase):
self.assertTrue(
any(phrase in logLine for logLine in logsContext.output)
)

def _test_normalizeGlyphsDirectoryNames(self, oldLayers, expectedLayers):
directory = tempfile.mkdtemp()
for _layerName, subDirectory in oldLayers:
Expand Down Expand Up @@ -1413,23 +1420,28 @@ def test_main_no_path(self):
with self.assertRaisesRegex(SystemExit, '2'):
with redirect_stderr(stream):
main([])
self.assertTrue("No input path" in stream.getvalue())
self.assertIn("the following arguments are required: input", stream.getvalue())

def test_main_input_does_not_exist(self):
stream = StringIO()
with self.assertRaisesRegex(SystemExit, '2'):
with redirect_stderr(stream):
with self.assertLogs(ufonormalizer.__name__, level="ERROR") as logs:
with self.assertRaisesRegex(SystemExit, '2'):
main(['foobarbazquz'])
self.assertTrue("Input path does not exist" in stream.getvalue())
self.assertLogsContain(logs, "Skipping non-existent input path")

def test_main_input_not_ufo(self):
# I use the path to the test module itself
existing_not_ufo_file = os.path.realpath(__file__)
with self.assertLogs(ufonormalizer.__name__, level="ERROR") as logs:
with self.assertRaisesRegex(SystemExit, '2'):
main([existing_not_ufo_file])
self.assertLogsContain(logs, "Skipping input path that isn't a UFO")

def test_main_multiple_inputs_and_output(self):
stream = StringIO()
with self.assertRaisesRegex(SystemExit, '2'):
with redirect_stderr(stream):
main([existing_not_ufo_file])
self.assertTrue("Input path is not a UFO" in stream.getvalue())
main(['--output', 'foo', 'bar', 'baz'])
self.assertIn("can't use -o/--output with multiple input UFOs", stream.getvalue())

def test_main_invalid_float_precision(self):
stream = StringIO()
Expand Down