Skip to content

Commit

Permalink
Merge pull request #34 from daltonmaag/no-modtimes
Browse files Browse the repository at this point in the history
add --float-precision option, fix duplicateUFO and add more tests
  • Loading branch information
miguelsousa committed Apr 8, 2016
2 parents 7e73825 + 1d6eeee commit b2c3eb4
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 16 deletions.
118 changes: 108 additions & 10 deletions normalization/test_ufonormalizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
_normalizeGlifPointAttributesFormat2,
_normalizeGlifComponentAttributesFormat2, _normalizeGlifTransformation,
_normalizeColorString, _convertPlistElementToObject, _normalizePlistFile,
main)
main, xmlDeclaration, plistDocType)
from ufonormalizer import __version__ as ufonormalizerVersion

# Python 3.4 deprecated readPlistFromBytes and writePlistToBytes
Expand All @@ -51,6 +51,32 @@
# Python 3: a stream of *unicode* strings
from io import StringIO

try:
from tempfile import TemporaryDirectory # Python 3 only
except ImportError:
# backport for Python 2.7
class TemporaryDirectory(object):
""" Create and return a temporary directory. This has the same
behavior as mkdtemp but can be used as a context manager.
Adapted from tempfile.TemporaryDirectory (new in Python 3.2).
"""
def __init__(self, suffix="", prefix="tmp", dir=None):
self._closed = False
self.name = tempfile.mkdtemp(suffix, prefix, dir)

def __enter__(self):
return self.name

def cleanup(self, _warn=False):
if self.name and not self._closed:
shutil.rmtree(self.name)
self._closed = True

def __exit__(self, exc, value, tb):
self.cleanup()


GLIFFORMAT1 = '''\
<?xml version="1.0" encoding="UTF-8"?>
<glyph name="period" format="1">
Expand Down Expand Up @@ -164,14 +190,18 @@
</plist>
'''

EMPTY_PLIST = '''\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
EMPTY_PLIST = "\n".join([xmlDeclaration, plistDocType, '<plist version="1.0"><dict></dict></plist>'])

METAINFO_PLIST = "\n".join([xmlDeclaration, plistDocType, """\
<plist version="1.0">
<dict>
</dict>
<dict>
<key>creator</key>
<string>org.robofab.ufoLib</string>
<key>formatVersion</key>
<integer>%d</integer>
</dict>
</plist>
'''
"""])


class redirect_stderr(object):
Expand Down Expand Up @@ -1386,6 +1416,73 @@ def test_main_input_not_ufo(self):
main([existing_not_ufo_file])
self.assertTrue("Input path is not a UFO" in stream.getvalue())

def test_main_invalid_float_precision(self):
stream = StringIO()
with TemporaryDirectory(suffix=".ufo") as tmp:
with self.assertRaisesRegex(SystemExit, '2'):
with redirect_stderr(stream):
main(['--float-precision', '-10', tmp])
self.assertTrue("float precision must be >= 0" in stream.getvalue())

def test_main_no_metainfo_plist(self):
with TemporaryDirectory(suffix=".ufo") as tmp:
with self.assertRaisesRegex(
UFONormalizerError, 'Required metainfo.plist file not in'):
main([tmp])

def test_main_metainfo_unsupported_formatVersion(self):
metainfo = METAINFO_PLIST % 1984
with TemporaryDirectory(suffix=".ufo") as tmp:
with open(os.path.join(tmp, "metainfo.plist"), 'w') as f:
f.write(metainfo)
with self.assertRaisesRegex(
UFONormalizerError, 'Unsupported UFO format'):
main([tmp])

def test_main_metainfo_no_formatVersion(self):
metainfo = EMPTY_PLIST
with TemporaryDirectory(suffix=".ufo") as tmp:
with open(os.path.join(tmp, "metainfo.plist"), 'w') as f:
f.write(metainfo)
with self.assertRaisesRegex(
UFONormalizerError, 'Required formatVersion value not defined'):
main([tmp])

def test_main_metainfo_invalid_formatVersion(self):
metainfo = "\n".join([xmlDeclaration, plistDocType, """\
<plist version="1.0">
<dict>
<key>formatVersion</key>
<string>foobar</string>
</dict>
</plist>"""])
with TemporaryDirectory(suffix=".ufo") as tmp:
with open(os.path.join(tmp, "metainfo.plist"), 'w') as f:
f.write(metainfo)
with self.assertRaisesRegex(
UFONormalizerError,
'Required formatVersion value not properly formatted'):
main([tmp])

def test_main_outputPath_duplicateUFO(self):
metainfo = METAINFO_PLIST % 3
with TemporaryDirectory(suffix=".ufo") as indir:
with open(os.path.join(indir, "metainfo.plist"), 'w') as f:
f.write(metainfo)
# same as input path
main(["-o", indir, indir])

# different but non existing path
outdir = os.path.join(indir, "output.ufo")
self.assertFalse(os.path.isdir(outdir))
main(["-o", outdir, indir])
self.assertTrue(os.path.exists(os.path.join(outdir, "metainfo.plist")))

# another existing dir
with TemporaryDirectory(suffix=".ufo") as outdir:
main(["-o", outdir, indir])
self.assertTrue(os.path.exists(os.path.join(outdir, "metainfo.plist")))


class XMLWriterTest(unittest.TestCase):
def __init__(self, methodName):
Expand Down Expand Up @@ -1638,6 +1735,10 @@ def test_xmlConvertFloat_custom_precision(self):
self.assertEqual(xmlConvertFloat(1.001), '1.001')
self.assertEqual(xmlConvertFloat(1.0001), '1')
self.assertEqual(xmlConvertFloat(1.0009), '1.001')
ufonormalizer.FLOAT_FORMAT = "%.0f"
self.assertEqual(xmlConvertFloat(1.001), '1')
self.assertEqual(xmlConvertFloat(1.9), '2')
self.assertEqual(xmlConvertFloat(10.0), '10')
ufonormalizer.FLOAT_FORMAT = oldFloatFormat

def test_xmlConvertInt(self):
Expand All @@ -1659,9 +1760,6 @@ def test_xmlConvertInt(self):
self.assertEqual(xmlConvertInt(0o0000030), '24')
self.assertEqual(xmlConvertInt(65536), '65536')

def test_duplicateUFO(self):
pass


class SubpathTest(unittest.TestCase):
def __init__(self, methodName):
Expand Down
27 changes: 21 additions & 6 deletions normalization/ufonormalizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,25 @@

def main(args=None):
import argparse

parser = argparse.ArgumentParser(description=description)
parser.add_argument("input", help="Path to a UFO to normalize.", nargs="?")
parser.add_argument("-t", "--test", help="Run the normalizer's internal tests.", action="store_true")
parser.add_argument("-o", "--output", help="Output path. If not given, the input path will be used.")
parser.add_argument("-a", "--all", help="Normalize all files in the UFO. By default, only files modified since the previous normalization will be processed.", action="store_true")
parser.add_argument("-v", "--verbose", help="Print more info to console.", action="store_true")
parser.add_argument("-q", "--quiet", help="Suppress all non-error messages.", action="store_true")
parser.add_argument("--float-precision", type=int, default=DEFAULT_FLOAT_PRECISION, help="Round floats to the specified number of decimal places (default is %d). The value -1 means no rounding (i.e. use built-in repr()." % DEFAULT_FLOAT_PRECISION)
args = parser.parse_args(args)

if args.test:
return runTests()

if args.verbose and args.quiet:
parser.error("--quiet and --verbose options are mutually exclusive.")
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)
Expand All @@ -60,6 +65,14 @@ def main(args=None):
parser.error('Input path does not exist: "%s".' % inputPath)
if os.path.splitext(inputPath)[-1].lower() != ".ufo":
parser.error('Input path is not a UFO: "%s".' % inputPath)

if args.float_precision >= 0:
floatPrecision = args.float_precision
elif args.float_precision == -1:
floatPrecision = None
else:
parser.error("float precision must be >= 0 or -1 (no round).")

message = 'Normalizing "%s".'
if not onlyModified:
message += " Processing all files."
Expand Down Expand Up @@ -142,10 +155,11 @@ def tounicode(s, encoding='ascii', errors='strict'):
class UFONormalizerError(Exception): pass


FLOAT_FORMAT = "%.10f"
DEFAULT_FLOAT_PRECISION = 10
FLOAT_FORMAT = "%%.%df" % DEFAULT_FLOAT_PRECISION


def normalizeUFO(ufoPath, outputPath=None, onlyModified=True, floatPrecision=10):
def normalizeUFO(ufoPath, outputPath=None, onlyModified=True, floatPrecision=DEFAULT_FLOAT_PRECISION):
global FLOAT_FORMAT
if floatPrecision is None:
# use repr() and don't round floats
Expand All @@ -157,7 +171,7 @@ def normalizeUFO(ufoPath, outputPath=None, onlyModified=True, floatPrecision=10)
# duplicate the UFO to the new place and work
# on the new file instead of trying to reconstruct
# the file one piece at a time.
if outputPath is not None:
if outputPath is not None and outputPath != ufoPath:
duplicateUFO(ufoPath, outputPath)
ufoPath = outputPath
# get the UFO format version
Expand Down Expand Up @@ -1303,9 +1317,10 @@ def xmlConvertFloat(value):
string = "%.16f" % value
else:
string = FLOAT_FORMAT % value
string = string.rstrip("0")
if string[-1] == ".":
return xmlConvertInt(int(value))
if "." in string:
string = string.rstrip("0")
if string[-1] == ".":
return xmlConvertInt(int(value))
return string

def xmlConvertInt(value):
Expand Down

0 comments on commit b2c3eb4

Please sign in to comment.