# converters: Conversion functions for kerning and groups

fontTools.ufoLib.converters.convertUFO1OrUFO2KerningToUFO3Kerning(kerning: dict[str, dict[str, int | float]], groups: dict[str, list[str]], glyphSet: Container[str] = ()) → tuple[dict[str, dict[str, int | float]], dict[str, list[str]], dict[str, dict[str, str]]]

  Convert kerning data in UFO1 or UFO2 syntax into UFO3 syntax.

  Parameters:

    - kerning – A dictionary containing the kerning rules defined in the UFO font, as used in `UFOReader` objects.

    - groups – A dictionary containing the groups defined in the UFO font, as used in `UFOReader` objects.

    - glyphSet – Optional; a set of glyph objects to skip (default: None).

  Returns:

    1. A dictionary representing the converted kerning data.

    2. A copy of the groups dictionary, with all groups renamed to UFO3 syntax.

    3. A dictionary containing the mapping of old group names to new group names.

fontTools.ufoLib.converters.findKnownKerningGroups(groups: Mapping[str, Any]) → tuple[set[str], set[str]]

  Find all kerning groups in a UFO1 or UFO2 font that use known prefixes.

  In some cases, not all kerning groups will be referenced by the kerning pairs in a UFO. The algorithm for locating groups in `convertUFO1OrUFO2KerningToUFO3Kerning()` will miss these unreferenced groups. By scanning for known prefixes, this function will catch all of the prefixed groups.

  The prefixes and sides by this function are:

  @MMK_L_ - side 1 @MMK_R_ - side 2

  as defined in the UFO1 specification.

  Parameters:

    groups – A dictionary containing the groups defined in the UFO font, as read by `UFOReader`.

  Returns:

    Two sets; the first containing the names of all first-side kerning groups identified in the `groups` dictionary, and the second containing the names of all second-side kerning groups identified.

    ”First-side” and “second-side” are with respect to the writing direction of the script.

    Example:

        >>> testGroups = {
        ...     "@MMK_L_1" : None,
        ...     "@MMK_L_2" : None,
        ...     "@MMK_L_3" : None,
        ...     "@MMK_R_1" : None,
        ...     "@MMK_R_2" : None,
        ...     "@MMK_R_3" : None,
        ...     "@MMK_l_1" : None,
        ...     "@MMK_r_1" : None,
        ...     "@MMK_X_1" : None,
        ...     "foo" : None,
        ... }
        >>> first, second = findKnownKerningGroups(testGroups)
        >>> sorted(first) == ['@MMK_L_1', '@MMK_L_2', '@MMK_L_3']
        True
        >>> sorted(second) == ['@MMK_R_1', '@MMK_R_2', '@MMK_R_3']
        True

fontTools.ufoLib.converters.makeUniqueGroupName(name: str, groupNames: list[str], counter: int = 0) → str

  Make a kerning group name that will be unique within the set of group names.

  If the requested kerning group name already exists within the set, this will return a new name by adding an incremented counter to the end of the requested name.

  Parameters:

    - name – The requested kerning group name.

    - groupNames – A list of the existing kerning group names.

    - counter – Optional; a counter of group names already seen (default: 0). If `counter` is not provided, the function will recurse, incrementing the value of `counter` until it finds the first unused `name+counter` combination, and return that result.

  Returns:

    A unique kerning group name composed of the requested name suffixed by the smallest available integer counter.

fontTools.ufoLib.converters.test()

  Tests for `convertUFO1OrUFO2KerningToUFO3Kerning()`.

  No known prefixes.

      >>> testKerning = {
      ...     "A" : {
      ...         "A" : 1,
      ...         "B" : 2,
      ...         "CGroup" : 3,
      ...         "DGroup" : 4
      ...     },
      ...     "BGroup" : {
      ...         "A" : 5,
      ...         "B" : 6,
      ...         "CGroup" : 7,
      ...         "DGroup" : 8
      ...     },
      ...     "CGroup" : {
      ...         "A" : 9,
      ...         "B" : 10,
      ...         "CGroup" : 11,
      ...         "DGroup" : 12
      ...     },
      ... }
      >>> testGroups = {
      ...     "BGroup" : ["B"],
      ...     "CGroup" : ["C"],
      ...     "DGroup" : ["D"],
      ... }
      >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning(
      ...     testKerning, testGroups, [])
      >>> expected = {
      ...     "A" : {
      ...         "A": 1,
      ...         "B": 2,
      ...         "public.kern2.CGroup": 3,
      ...         "public.kern2.DGroup": 4
      ...     },
      ...     "public.kern1.BGroup": {
      ...         "A": 5,
      ...         "B": 6,
      ...         "public.kern2.CGroup": 7,
      ...         "public.kern2.DGroup": 8
      ...     },
      ...     "public.kern1.CGroup": {
      ...         "A": 9,
      ...         "B": 10,
      ...         "public.kern2.CGroup": 11,
      ...         "public.kern2.DGroup": 12
      ...     }
      ... }
      >>> kerning == expected
      True
      >>> expected = {
      ...     "BGroup": ["B"],
      ...     "CGroup": ["C"],
      ...     "DGroup": ["D"],
      ...     "public.kern1.BGroup": ["B"],
      ...     "public.kern1.CGroup": ["C"],
      ...     "public.kern2.CGroup": ["C"],
      ...     "public.kern2.DGroup": ["D"],
      ... }
      >>> groups == expected
      True

  Known prefixes.

      >>> testKerning = {
      ...     "A" : {
      ...         "A" : 1,
      ...         "B" : 2,
      ...         "@MMK_R_CGroup" : 3,
      ...         "@MMK_R_DGroup" : 4
      ...     },
      ...     "@MMK_L_BGroup" : {
      ...         "A" : 5,
      ...         "B" : 6,
      ...         "@MMK_R_CGroup" : 7,
      ...         "@MMK_R_DGroup" : 8
      ...     },
      ...     "@MMK_L_CGroup" : {
      ...         "A" : 9,
      ...         "B" : 10,
      ...         "@MMK_R_CGroup" : 11,
      ...         "@MMK_R_DGroup" : 12
      ...     },
      ... }
      >>> testGroups = {
      ...     "@MMK_L_BGroup" : ["B"],
      ...     "@MMK_L_CGroup" : ["C"],
      ...     "@MMK_L_XGroup" : ["X"],
      ...     "@MMK_R_CGroup" : ["C"],
      ...     "@MMK_R_DGroup" : ["D"],
      ...     "@MMK_R_XGroup" : ["X"],
      ... }
      >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning(
      ...     testKerning, testGroups, [])
      >>> expected = {
      ...     "A" : {
      ...         "A": 1,
      ...         "B": 2,
      ...         "public.kern2.CGroup": 3,
      ...         "public.kern2.DGroup": 4
      ...     },
      ...     "public.kern1.BGroup": {
      ...         "A": 5,
      ...         "B": 6,
      ...         "public.kern2.CGroup": 7,
      ...         "public.kern2.DGroup": 8
      ...     },
      ...     "public.kern1.CGroup": {
      ...         "A": 9,
      ...         "B": 10,
      ...         "public.kern2.CGroup": 11,
      ...         "public.kern2.DGroup": 12
      ...     }
      ... }
      >>> kerning == expected
      True
      >>> expected = {
      ...     "@MMK_L_BGroup": ["B"],
      ...     "@MMK_L_CGroup": ["C"],
      ...     "@MMK_L_XGroup": ["X"],
      ...     "@MMK_R_CGroup": ["C"],
      ...     "@MMK_R_DGroup": ["D"],
      ...     "@MMK_R_XGroup": ["X"],
      ...     "public.kern1.BGroup": ["B"],
      ...     "public.kern1.CGroup": ["C"],
      ...     "public.kern1.XGroup": ["X"],
      ...     "public.kern2.CGroup": ["C"],
      ...     "public.kern2.DGroup": ["D"],
      ...     "public.kern2.XGroup": ["X"],
      ... }
      >>> groups == expected
      True

      >>> from .validators import kerningValidator
      >>> kerningValidator(kerning)
      (True, None)

  Mixture of known prefixes and groups without prefixes.

      >>> testKerning = {
      ...     "A" : {
      ...         "A" : 1,
      ...         "B" : 2,
      ...         "@MMK_R_CGroup" : 3,
      ...         "DGroup" : 4
      ...     },
      ...     "BGroup" : {
      ...         "A" : 5,
      ...         "B" : 6,
      ...         "@MMK_R_CGroup" : 7,
      ...         "DGroup" : 8
      ...     },
      ...     "@MMK_L_CGroup" : {
      ...         "A" : 9,
      ...         "B" : 10,
      ...         "@MMK_R_CGroup" : 11,
      ...         "DGroup" : 12
      ...     },
      ... }
      >>> testGroups = {
      ...     "BGroup" : ["B"],
      ...     "@MMK_L_CGroup" : ["C"],
      ...     "@MMK_R_CGroup" : ["C"],
      ...     "DGroup" : ["D"],
      ... }
      >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning(
      ...     testKerning, testGroups, [])
      >>> expected = {
      ...     "A" : {
      ...         "A": 1,
      ...         "B": 2,
      ...         "public.kern2.CGroup": 3,
      ...         "public.kern2.DGroup": 4
      ...     },
      ...     "public.kern1.BGroup": {
      ...         "A": 5,
      ...         "B": 6,
      ...         "public.kern2.CGroup": 7,
      ...         "public.kern2.DGroup": 8
      ...     },
      ...     "public.kern1.CGroup": {
      ...         "A": 9,
      ...         "B": 10,
      ...         "public.kern2.CGroup": 11,
      ...         "public.kern2.DGroup": 12
      ...     }
      ... }
      >>> kerning == expected
      True
      >>> expected = {
      ...     "BGroup": ["B"],
      ...     "@MMK_L_CGroup": ["C"],
      ...     "@MMK_R_CGroup": ["C"],
      ...     "DGroup": ["D"],
      ...     "public.kern1.BGroup": ["B"],
      ...     "public.kern1.CGroup": ["C"],
      ...     "public.kern2.CGroup": ["C"],
      ...     "public.kern2.DGroup": ["D"],
      ... }
      >>> groups == expected
      True