Beispiel #1
0
def test_loadFilters_args_missing(ufo):
    del ufo.lib[UFO2FT_FILTERS_KEY][0]["args"]

    with pytest.raises(TypeError) as exc_info:
        loadFilters(ufo)

    assert exc_info.match("missing")
Beispiel #2
0
def test_loadFilters_failed(ufo):
    ufo.lib[UFO2FT_FILTERS_KEY].append(dict(name="Non Existent"))

    with CapturingLogHandler(logger, level="ERROR") as captor:
        loadFilters(ufo)

    captor.assertRegex("Failed to load filter")
Beispiel #3
0
def test_loadFilters_args_unsupported(ufo):
    ufo.lib[UFO2FT_FILTERS_KEY][0]["args"].append("baz")

    with pytest.raises(TypeError) as exc_info:
        loadFilters(ufo)

    assert exc_info.match('unsupported')
Beispiel #4
0
def test_loadFilters_both_include_exclude(ufo):
    ufo.lib[UFO2FT_FILTERS_KEY][0]["include"] = ["a", "b"]
    ufo.lib[UFO2FT_FILTERS_KEY][0]["exclude"] = ["c", "d"]

    with pytest.raises(ValueError) as exc_info:
        loadFilters(ufo)

    assert exc_info.match("arguments are mutually exclusive")
Beispiel #5
0
def test_loadFilters_args_as_duplicated_keywords(ufo):
    ufo.lib[FILTERS_KEY][0]["args"] = ["foo"]
    ufo.lib[FILTERS_KEY][0]["kwargs"] = {"a": "foo", "b": "bar"}

    with pytest.raises(TypeError) as exc_info:
        loadFilters(ufo)

    assert exc_info.match("duplicated")
Beispiel #6
0
def test_loadFilters_kwargs_unsupported(ufo):
    ufo.lib[UFO2FT_FILTERS_KEY][0]["kwargs"] = {}
    ufo.lib[UFO2FT_FILTERS_KEY][0]["kwargs"]["c"] = 1
    ufo.lib[UFO2FT_FILTERS_KEY][0]["kwargs"]["d"] = 2  # unknown

    with pytest.raises(TypeError) as exc_info:
        loadFilters(ufo)

    assert exc_info.match("got an unsupported keyword")
Beispiel #7
0
 def __init__(self, ufo, inplace=False, layerName=None, **kwargs):
     self.ufo = ufo
     self.inplace = inplace
     self.layerName = layerName
     self.glyphSet = _GlyphSet.from_layer(ufo, layerName, copy=not inplace)
     self.defaultFilters = self.initDefaultFilters(**kwargs)
     self.preFilters, self.postFilters = loadFilters(ufo)
Beispiel #8
0
 def __init__(self, ufo, inplace=False, **kwargs):
     self.ufo = ufo
     if inplace:
         self.glyphSet = {g.name: g for g in ufo}
     else:
         self.glyphSet = {g.name: _copyGlyph(g) for g in ufo}
     self.defaultFilters = self.initDefaultFilters(**kwargs)
     self.preFilters, self.postFilters = loadFilters(ufo)
Beispiel #9
0
def test_loadFilters_exclude_list(ufo):
    ufo.lib[UFO2FT_FILTERS_KEY][0]["exclude"] = ["a", "b"]

    _, [filter_obj] = loadFilters(ufo)

    assert not filter_obj.include(MockGlyph(name="a"))
    assert not filter_obj.include(MockGlyph(name="b"))
    assert filter_obj.include(MockGlyph(name="c"))
Beispiel #10
0
def test_loadFilters_args_as_keywords(ufo):
    del ufo.lib[FILTERS_KEY][0]["args"]
    ufo.lib[FILTERS_KEY][0]["kwargs"] = {"a": "foo", "b": "bar"}

    _, [filter_obj] = loadFilters(ufo)

    assert filter_obj.options.a == "foo"
    assert filter_obj.options.b == "bar"
    def __init__(
        self,
        ufos,
        inplace=False,
        flattenComponents=False,
        conversionError=None,
        reverseDirection=True,
        rememberCurveType=True,
        layerNames=None,
        skipExportGlyphs=None,
        filters=None,
    ):
        from cu2qu.ufo import DEFAULT_MAX_ERR

        self.ufos = ufos
        self.inplace = inplace
        self.flattenComponents = flattenComponents

        if layerNames is None:
            layerNames = [None] * len(ufos)
        assert len(ufos) == len(layerNames)
        self.layerNames = layerNames

        self.glyphSets = [
            _GlyphSet.from_layer(
                ufo, layerName, copy=not inplace, skipExportGlyphs=skipExportGlyphs
            )
            for ufo, layerName in zip(ufos, layerNames)
        ]
        self._conversionErrors = [
            (conversionError or DEFAULT_MAX_ERR)
            * getAttrWithFallback(ufo.info, "unitsPerEm")
            for ufo in ufos
        ]
        self._reverseDirection = reverseDirection
        self._rememberCurveType = rememberCurveType

        self.preFilters, self.postFilters = [], []
        if filters is None:
            for ufo in ufos:
                pre, post = loadFilters(ufo)
                self.preFilters.append(pre)
                self.postFilters.append(post)
        else:
            pre = [f for f in filters if f.pre]
            post = [f for f in filters if not f.pre]
            for _ in ufos:
                self.preFilters.append(pre)
                self.postFilters.append(post)
Beispiel #12
0
def test_loadFilters_custom_namespace(ufo):
    ufo.lib[UFO2FT_FILTERS_KEY][0]["name"] = "Self Destruct"
    ufo.lib[UFO2FT_FILTERS_KEY][0]["namespace"] = "my_dangerous_filters"

    class SelfDestructFilter(FooBarFilter):
        def filter(glyph):
            # Don't try this at home!!! LOL :)
            # shutil.rmtree(os.path.expanduser("~"))
            return True

    with _TempModule("my_dangerous_filters"), \
            _TempModule("my_dangerous_filters.selfDestruct") as temp:
        temp.module.__dict__["SelfDestructFilter"] = SelfDestructFilter

        _, [filter_obj] = loadFilters(ufo)

    assert isinstance(filter_obj, SelfDestructFilter)
 def __init__(
     self,
     ufo,
     inplace=False,
     layerName=None,
     skipExportGlyphs=None,
     filters=None,
     **kwargs
 ):
     self.ufo = ufo
     self.inplace = inplace
     self.layerName = layerName
     self.glyphSet = _GlyphSet.from_layer(
         ufo, layerName, copy=not inplace, skipExportGlyphs=skipExportGlyphs
     )
     self.defaultFilters = self.initDefaultFilters(**kwargs)
     if filters is None:
         self.preFilters, self.postFilters = loadFilters(ufo)
     else:
         self.preFilters = [f for f in filters if f.pre]
         self.postFilters = [f for f in filters if not f.pre]
Beispiel #14
0
    def __init__(
        self,
        ufos,
        inplace=False,
        conversionError=None,
        reverseDirection=True,
        rememberCurveType=True,
        layerNames=None,
        skipExportGlyphs=None,
    ):
        from cu2qu.ufo import DEFAULT_MAX_ERR

        self.ufos = ufos
        self.inplace = inplace

        if layerNames is None:
            layerNames = [None] * len(ufos)
        assert len(ufos) == len(layerNames)
        self.layerNames = layerNames

        self.glyphSets = [
            _GlyphSet.from_layer(ufo,
                                 layerName,
                                 copy=not inplace,
                                 skipExportGlyphs=skipExportGlyphs)
            for ufo, layerName in zip(ufos, layerNames)
        ]
        self._conversionErrors = [
            (conversionError or DEFAULT_MAX_ERR) * ufo.info.unitsPerEm
            for ufo in ufos
        ]
        self._reverseDirection = reverseDirection
        self._rememberCurveType = rememberCurveType

        self.preFilters, self.postFilters = [], []
        for ufo in ufos:
            pre, post = loadFilters(ufo)
            self.preFilters.append(pre)
            self.postFilters.append(post)
Beispiel #15
0
def test_loadFilters_pre(ufo):
    ufo.lib[UFO2FT_FILTERS_KEY][0]["pre"] = True
    pre, post = loadFilters(ufo)
    assert len(pre) == 1
    assert not post
    assert isinstance(pre[0], FooBarFilter)
Beispiel #16
0
def test_loadFilters_empty():
    ufo = MockFont(lib={})
    assert UFO2FT_FILTERS_KEY not in ufo.lib
    assert loadFilters(ufo) == ([], [])
Beispiel #17
0
    def run_from_designspace(
        self,
        designspace_path,
        output=(),
        interpolate=False,
        masters_as_instances=False,
        interpolate_binary_layout=False,
        round_instances=False,
        feature_writers=None,
        filters=None,
        expand_features_to_instances=False,
        use_mutatormath=False,
        **kwargs,
    ):
        """Run toolchain from a DesignSpace document to produce either static
        instance fonts (ttf or otf), interpolatable or variable fonts.

        Args:
            designspace_path: Path to designspace document.
            interpolate: If True output all instance fonts, otherwise just
                masters. If the value is a string, only build instance(s) that
                match given name. The string is compiled into a regular
                expression and matched against the "name" attribute of
                designspace instances using `re.fullmatch`.
            masters_as_instances: If True, output master fonts as instances.
            interpolate_binary_layout: Interpolate layout tables from compiled
                master binaries.
            round_instances: apply integer rounding when interpolating with
                MutatorMath.
            kwargs: Arguments passed along to run_from_ufos.

        Raises:
            TypeError: "variable" or "interpolatable" outputs are incompatible
                with arguments "interpolate", "masters_as_instances", and
                "interpolate_binary_layout".
        """

        interp_outputs = INTERPOLATABLE_OUTPUTS.intersection(output)
        static_outputs = set(output).difference(interp_outputs)
        if interp_outputs:
            for argname in (
                "interpolate",
                "masters_as_instances",
                "interpolate_binary_layout",
            ):
                if locals()[argname]:
                    raise TypeError(
                        '"%s" argument incompatible with output %r'
                        % (argname, ", ".join(sorted(interp_outputs)))
                    )

        try:
            designspace = designspaceLib.DesignSpaceDocument.fromfile(designspace_path)
        except Exception as e:
            raise FontmakeError("Reading Designspace failed", designspace_path) from e

        # if no --feature-writers option was passed, check in the designspace's
        # <lib> element if user supplied a custom featureWriters configuration;
        # if so, use that for all the UFOs built from this designspace
        if feature_writers is None and FEATURE_WRITERS_KEY in designspace.lib:
            feature_writers = loadFeatureWriters(designspace)

        if filters is None and FILTERS_KEY in designspace.lib:
            preFilters, postFilters = loadFilters(designspace)
            filters = preFilters + postFilters

        try:
            if static_outputs:
                self._run_from_designspace_static(
                    designspace,
                    outputs=static_outputs,
                    interpolate=interpolate,
                    masters_as_instances=masters_as_instances,
                    interpolate_binary_layout=interpolate_binary_layout,
                    round_instances=round_instances,
                    feature_writers=feature_writers,
                    expand_features_to_instances=expand_features_to_instances,
                    use_mutatormath=use_mutatormath,
                    filters=filters,
                    **kwargs,
                )
            if interp_outputs:
                self._run_from_designspace_interpolatable(
                    designspace,
                    outputs=interp_outputs,
                    feature_writers=feature_writers,
                    filters=filters,
                    **kwargs,
                )
        except FontmakeError as e:
            # Some called functions already added the Designspace file to the source
            # trail.
            if e.source_trail[-1] != designspace.path:
                e.source_trail.append(designspace.path)
            raise
        except Exception as e:
            raise FontmakeError(
                "Generating fonts from Designspace failed", designspace.path
            ) from e
Beispiel #18
0
def test_loadFilters_include_all(ufo):
    _, [filter_obj] = loadFilters(ufo)

    assert filter_obj.include(MockGlyph(name="hello"))
    assert filter_obj.include(MockGlyph(name="world"))