Esempio n. 1
0
def modify_linegap_percent(fontpath, percent):
    try:
        tt = ttLib.TTFont(fontpath)

        # get observed start values from the font
        os2_typo_ascender = tt['OS/2'].__dict__['sTypoAscender']
        os2_typo_descender = tt['OS/2'].__dict__['sTypoDescender']

        # redefine hhea linegap to 0
        hhea_linegap = 0

        factor = 1.0 * int(percent) / 100

        os2_typo_linegap = int(factor * (os2_typo_ascender + -(os2_typo_descender)))
        total_height = os2_typo_ascender + -(os2_typo_descender) + os2_typo_linegap

        hhea_ascent = int(os2_typo_ascender + 0.5 * os2_typo_linegap)
        hhea_descent = -(total_height - hhea_ascent)

        os2_win_ascent = hhea_ascent
        os2_win_descent = -hhea_descent

        # define updated values
        tt['hhea'].__dict__['lineGap'] = hhea_linegap
        tt['OS/2'].__dict__['sTypoLineGap'] = os2_typo_linegap
        tt['OS/2'].__dict__['usWinAscent'] = os2_win_ascent
        tt['OS/2'].__dict__['usWinDescent'] = os2_win_descent
        tt['hhea'].__dict__['ascent'] = hhea_ascent
        tt['hhea'].__dict__['descent'] = hhea_descent

        tt.save(get_linegap_percent_filepath(fontpath, percent))
        return True
    except Exception as e:  # pragma: no cover
        stderr("[font-line] ERROR: Unable to modify the line spacing in the font file '" + fontpath + "'. " + str(e))
        sys.exit(1)
def test_stderr_unicode(capsys):
    if sys.version_info[0] == 2:
        msg = u"カイダーディー"
    else:
        msg = "カイダーディー"
    stderr(msg)
    out, err = capsys.readouterr()
    assert err == msg + "\n"
def test_stderr_unicode(capsys):
    if sys.version_info[0] == 2:
        msg = u"カイダーディー"
    else:
        msg = "カイダーディー"
    stderr(msg)
    out, err = capsys.readouterr()
    assert err == msg + "\n"
def test_stderr_ascii_reports_correct_statuscode_minusone(capsys):
    with pytest.raises(SystemExit):
        try:
            stderr("This is a test message", statuscode=-1)
            out, err = capsys.readouterr()
            assert err == "This is a test message\n"
        except SystemExit as exit_code:
            assert exit_code.__str__() == '-1'  # tests the exit status code in the SystemExit exception
            raise exit_code
def test_stderr_ascii_reports_correct_statuscode_minusone(capsys):
    with pytest.raises(SystemExit):
        try:
            stderr("This is a test message", statuscode=-1)
            out, err = capsys.readouterr()
            assert err == "This is a test message\n"
        except SystemExit as exit_code:
            assert exit_code.__str__(
            ) == '-1'  # tests the exit status code in the SystemExit exception
            raise exit_code
def test_stderr_unicode_reports_correct_statuscode(capsys):
    if sys.version_info[0] == 2:
        msg = u"カイダーディー"
    else:
        msg = "カイダーディー"
    with pytest.raises(SystemExit):
        try:
            stderr(msg, statuscode=1)
            out, err = capsys.readouterr()
            assert err == msg + "\n"
        except SystemExit as exit_code:
            assert exit_code.__str__() == '1'  # tests the exit status code in the SystemExit exception
            raise exit_code
def test_stderr_unicode_reports_correct_statuscode(capsys):
    if sys.version_info[0] == 2:
        msg = u"カイダーディー"
    else:
        msg = "カイダーディー"
    with pytest.raises(SystemExit):
        try:
            stderr(msg, statuscode=1)
            out, err = capsys.readouterr()
            assert err == msg + "\n"
        except SystemExit as exit_code:
            assert exit_code.__str__(
            ) == '1'  # tests the exit status code in the SystemExit exception
            raise exit_code
Esempio n. 8
0
def get_git_root_path():
    """
    Recursively searches for git root path over 4 directory levels above working directory
    :return: validated git root path as string OR raises SystemExit if not found
    """
    try:
        # begin by defining current working directory as root of git repository
        unverified_gitroot_path = os.path.abspath(".")

        # check to see if this assumption is correct
        if dir_exists(os.path.join(unverified_gitroot_path, ".git")):
            verified_gitroot_path = os.path.join(unverified_gitroot_path,
                                                 ".git")
        else:  # if not, recursive search up to three directories above for the git repo root
            one_level_up = os.path.abspath(
                os.path.join(unverified_gitroot_path, os.pardir))
            two_levels_up = os.path.dirname(one_level_up)
            three_levels_up = os.path.dirname(two_levels_up)

            one_level_up_path = os.path.join(one_level_up, ".git")
            two_levels_up_path = os.path.join(two_levels_up, ".git")
            three_levels_up_path = os.path.join(three_levels_up, ".git")

            if dir_exists(one_level_up_path):  # check one directory level up
                verified_gitroot_path = os.path.dirname(one_level_up_path)
            elif dir_exists(
                    two_levels_up_path):  # check two directory levels up
                verified_gitroot_path = os.path.dirname(two_levels_up_path)
            elif dir_exists(
                    three_levels_up_path):  # check three directory levels up
                verified_gitroot_path = os.path.dirname(three_levels_up_path)
            else:
                stderr(
                    "[ufodiff] ERROR: Unable to identify the root of your git repository. Please try again from "
                    "the root of your repository")
                sys.exit(1)
    except Exception as e:
        stderr(
            "[ufodiff] ERROR: Unable to identify the root of your git repository. Please try again from "
            "the root of your repository. " + str(e))
        sys.exit(1)

    return verified_gitroot_path
Esempio n. 9
0
def validate_commit_number(commits_number):
    """
    Validates commit number entered by user following `commits:` argument as valid integer and within appropriate range

    :param commits_number: string that was entered by user following `commits:` argument
    :return: no return object, raises SystemExit for all errors detected
    """
    if (
            not commits_number.isdigit()
    ):  # validate that user entered number of commits for diff is an integer
        stderr(
            "[ufodiff] ERROR: The value following the colon in the 'commits:[number]' argument is not a valid "
            "integer value")
        sys.exit(1)
    elif (int(commits_number) == 0 or int(commits_number) <
          0):  # validate that the number of commits is > 0
        stderr(
            "[ufodiff] ERROR: Please define a value over zero for the commit history"
        )
        sys.exit(1)
Esempio n. 10
0
def validate_diff_commands_args(command_obj):
    """
    Validates arguments for any diff/diffnc command requested by user.  It provides user error
    messages and raises SystemExit for erroneous command entry at the command line.

    :param command_obj: a commandlines library Command object
    :return: no return object, SystemExit raised for all errors detected
    """
    # argument validations
    if command_obj.argc < 2:
        stderr("[ufodiff] ERROR: Missing arguments.")
        sys.exit(1)
    if command_obj.arg1.startswith("commits:"):
        if len(command_obj.arg1) < 9:
            stderr(
                "[ufodiff] ERROR: Please include an integer after the colon in the 'commits:[number]' argument"
            )
            sys.exit(1)
        else:
            commits_list = command_obj.arg1.split(":")
            commits_number = commits_list[1]
            # validate the number of commits as an integer value, exit with error message if not an integer
            validate_commit_number(commits_number)
    if command_obj.arg1.startswith("branch:"):
        if len(command_obj.arg1) < 8:
            stderr(
                "[ufodiff] ERROR: Please include the name of a git branch following the colon in the "
                "'branch:[name]' argument")
            sys.exit(1)
def test_stderr_ascii(capsys):
    stderr("This is a test message")
    out, err = capsys.readouterr()
    assert err == "This is a test message\n"
def test_stderr_bad_object_as_statuscode():
    with pytest.raises(NameError):
        stderr("This is a test message", statuscode=bogusobj)
Esempio n. 13
0
def validate_delta_commands_args(command_obj):
    """
    Validates arguments for any delta/deltajson/deltamd command requested by user.  It provides
    user error messages and raises SystemExit for erroneous command entry at the command line.

    :param command_obj: a commandlines library Command object
    :return: no return object, SystemExit raised for all errors detected
    """
    acceptable_deltacommands = ["all"
                                ]  # used in command line argument validations
    # Command line argument validations
    if command_obj.argc < 3:  # expected argument number
        stderr("[ufodiff] ERROR: Missing arguments.")
        sys.exit(1)
    if (command_obj.arg1 not in acceptable_deltacommands
        ):  # acceptable sub command to delta
        stderr("[ufodiff] ERROR: 'ufodiff " + command_obj.arg0 + " " +
               command_obj.arg1 + "' is not a valid request")
        stderr("Acceptable arguments to " + command_obj.arg0 + " include:")
        for acceptable_deltacommand in acceptable_deltacommands:
            stderr(" " + acceptable_deltacommand)
        sys.exit(1)
    if command_obj.arg2.startswith("commits:"):
        commits_list = command_obj.arg2.split(":")
        if (len(commits_list) == 2 and commits_list[1]
                == ""):  # does not include a value following the colon
            stderr(
                "[ufodiff] ERROR: Please include an integer value following the 'commits:' argument"
            )
            sys.exit(1)
        else:
            commits_number = commits_list[1]
            validate_commit_number(commits_number)
    elif command_obj.arg2.startswith("branch:"):
        branch_list = command_obj.arg2.split(":")
        if len(branch_list) == 2 and branch_list[1] == "":
            stderr(
                "[ufodiff] ERROR: Please include the name of an existing git branch following the 'branch:' argument"
            )
            sys.exit(1)
    else:
        stderr(
            "[ufodiff] ERROR: Please include either the 'commits:' or 'branch:' argument in the command"
        )
        sys.exit(1)
Esempio n. 14
0
def modify_linegap_percent(fontpath, percent):
    try:
        tt = ttLib.TTFont(fontpath)

        # get observed start values from the font
        os2_typo_ascender = tt['OS/2'].sTypoAscender
        os2_typo_descender = tt['OS/2'].sTypoDescender
        os2_typo_linegap = tt['OS/2'].sTypoLineGap
        hhea_ascent = tt['hhea'].ascent
        hhea_descent = tt['hhea'].descent
        units_per_em = tt['head'].unitsPerEm

        # calculate necessary delta values
        os2_typo_ascdesc_delta = os2_typo_ascender + -(os2_typo_descender)
        hhea_ascdesc_delta = hhea_ascent + -(hhea_descent)

        # define percent UPM from command line request
        factor = 1.0 * int(percent) / 100

        # define line spacing units
        line_spacing_units = int(factor * units_per_em)

        # define total height as UPM + line spacing units
        total_height = line_spacing_units + units_per_em

        # height calculations for adjustments
        delta_height = total_height - hhea_ascdesc_delta
        upper_lower_add_units = int(0.5 * delta_height)

        # redefine hhea linegap to 0 in all cases
        hhea_linegap = 0

        # Define metrics based upon original design approach in the font
        # Google metrics approach
        if os2_typo_linegap == 0 and (os2_typo_ascdesc_delta > units_per_em):
            # define values
            os2_typo_ascender += upper_lower_add_units
            os2_typo_descender -= upper_lower_add_units
            hhea_ascent += upper_lower_add_units
            hhea_descent -= upper_lower_add_units
            os2_win_ascent = hhea_ascent
            os2_win_descent = -hhea_descent
        # Adobe metrics approach
        elif os2_typo_linegap == 0 and (os2_typo_ascdesc_delta == units_per_em):
            hhea_ascent += upper_lower_add_units
            hhea_descent -= upper_lower_add_units
            os2_win_ascent = hhea_ascent
            os2_win_descent = -hhea_descent
        else:
            os2_typo_linegap = line_spacing_units
            hhea_ascent = int(os2_typo_ascender + 0.5 * os2_typo_linegap)
            hhea_descent = -(total_height - hhea_ascent)
            os2_win_ascent = hhea_ascent
            os2_win_descent = -hhea_descent

        # define updated values from above calculations
        tt['hhea'].lineGap = hhea_linegap
        tt['OS/2'].sTypoAscender = os2_typo_ascender
        tt['OS/2'].sTypoDescender = os2_typo_descender
        tt['OS/2'].sTypoLineGap = os2_typo_linegap
        tt['OS/2'].usWinAscent = os2_win_ascent
        tt['OS/2'].usWinDescent = os2_win_descent
        tt['hhea'].ascent = hhea_ascent
        tt['hhea'].descent = hhea_descent

        tt.save(get_linegap_percent_filepath(fontpath, percent))
        return True
    except Exception as e:  # pragma: no cover
        stderr("[font-line] ERROR: Unable to modify the line spacing in the font file '" + fontpath + "'. " + str(e))
        sys.exit(1)
def test_stderr_capsysfail(
        capsys):  # confirm that capsys capturing standard out appropriately
    stderr("bogus text for a test")
    out, err = capsys.readouterr()
    assert err != "something else"
    assert err == "bogus text for a test\n"
def test_stderr_ascii(capsys):
    stderr("This is a test message")
    out, err = capsys.readouterr()
    assert err == "This is a test message\n"
def test_stderr_bad_object_as_statuscode():
    with pytest.raises(NameError):
        stderr("This is a test message", statuscode=bogusobj)
Esempio n. 18
0
def main():
    """Defines the logic for the `ufodiff` command line executable"""
    c = Command()

    if c.does_not_validate_missing_args():
        stderr(
            "[ufodiff] ERROR: Please include the appropriate arguments with your command."
        )
        sys.exit(1)

    if c.is_help_request():
        stdout(settings.HELP)
        sys.exit(0)
    elif c.is_version_request():
        stdout(settings.VERSION)
        sys.exit(0)
    elif c.is_usage_request():
        stdout(settings.USAGE)
        sys.exit(0)

    # DELTA + DELTAJSON + DELTAMD sub-commands
    if c.subcmd in {"delta", "deltajson", "deltamd"}:
        # argument validation
        validate_delta_commands_args(c)
        # create list for UFO filtered analyses as requested by user
        ufo_directory_list = []
        for arg in c.argv:
            if arg.endswith(".ufo"):
                ufo_directory_list.append(arg)

        # flags for type of test
        is_branch_test = False
        is_commits_test = False

        if c.arg2.startswith("commits:"):
            is_commits_test = True
            commits_list = c.arg2.split(":")
            commit_number = commits_list[1]
        elif c.arg2.startswith("branch:"):
            is_branch_test = True
            branch_list = c.arg2.split(":")
            branch_name = branch_list[1]
        # else:
        #     pass  # TODO: add direct git idiom call support

        # recursive search for the root of the git repository x 3 levels if not found in working directory
        verified_gitroot_path = get_git_root_path()

        # perform the delta analysis on the repository, different object for commits vs branch tests
        if is_commits_test is True:
            delta = Delta(
                verified_gitroot_path,
                ufo_directory_list,
                is_commit_test=True,
                commit_number=commit_number,
            )
        elif is_branch_test is True:
            delta = Delta(
                verified_gitroot_path,
                ufo_directory_list,
                is_branch_test=True,
                compare_branch_name=branch_name,
            )

        if c.arg1 == "all":
            if c.subcmd == "delta":
                sys.stdout.write(delta.get_stdout_string(write_format="text"))
            elif c.subcmd == "deltajson":
                sys.stdout.write(delta.get_stdout_string(write_format="json"))
            elif c.subcmd == "deltamd":
                sys.stdout.write(
                    delta.get_stdout_string(write_format="markdown"))
        # elif c.arg1 == "glyph":
        #     pass  # TODO: implement glyph only command handling with 'ufo delta glyph'
        # elif c.arg1 == "nonglyph":
        #     pass  # TODO: implement nonglyph only command handling with 'ufo delta nonglyph'
    # DIFF SUBCOMMAND
    elif c.subcmd == "diff":
        # argument validation
        validate_diff_commands_args(c)
        # execute the command
        try:
            verified_gitroot_path = get_git_root_path()
            diff = Diff(verified_gitroot_path, color_diff=True)
            for diff_string in diff.get_diff_string_generator(c.arg1):
                stdout(diff_string)
        except Exception as e:
            stderr(
                "[ufodiff] ERROR: Unable to excecute your request. Error returned as: "
                + os.linesep + str(e))
            sys.exit(1)
    # DIFFNC SUBCOMMAND
    elif c.subcmd == "diffnc":
        # argument validations
        validate_diff_commands_args(c)
        # execute the command
        try:
            verified_gitroot_path = get_git_root_path()
            diff = Diff(verified_gitroot_path, color_diff=False)
            for diff_string in diff.get_diff_string_generator(c.arg1):
                stdout(diff_string)
        except Exception as e:
            stderr(
                "[ufodiff] ERROR: Unable to excecute your request. Error returned as: "
                + os.linesep + str(e))
            sys.exit(1)
    # # DIFF-FILE SUBCOMMAND
    # elif c.subcmd == "diff-filter":  # user specified file/directory filters on the diff performed
    #     pass
    # # DIFF-FILENC SUBCOMMAND
    # elif c.subcmd == "diff-filternc":
    #     pass
    sys.exit(0)
Esempio n. 19
0
def main():
    """Defines the logic for the `font-line` command line executable"""
    c = Command()

    if c.does_not_validate_missing_args():
        stderr(
            "[font-line] ERROR: Please include one or more arguments with your command."
        )
        sys.exit(1)

    if c.is_help_request():
        stdout(settings.HELP)
        sys.exit(0)
    elif c.is_version_request():
        stdout(settings.VERSION)
        sys.exit(0)
    elif c.is_usage_request():
        stdout(settings.USAGE)
        sys.exit(0)

    # REPORT sub-command
    if c.subcmd == "report":
        if c.argc < 2:
            stderr(
                "[font-line] ERROR: Missing file path argument(s) after the "
                "report subcommand.")
            sys.exit(1)
        else:
            for fontpath in c.argv[1:]:
                # test for existence of file on path
                if file_exists(fontpath):
                    # test that filepath includes file of a supported file type
                    if is_supported_filetype(fontpath):
                        stdout(get_font_report(fontpath))
                    else:
                        stderr(
                            "[font-line] ERROR: '" + fontpath +
                            "' does not appear to be a supported font file type."
                        )
                else:
                    stderr("[font-line] ERROR: '" + fontpath +
                           "' does not appear to be a valid filepath.")
    # PERCENT sub-command
    elif c.subcmd == "percent":
        if c.argc < 3:
            stderr("[font-line] ERROR: Not enough arguments.")
            sys.exit(1)
        else:
            percent = c.argv[1]
            # test the percent integer argument
            try:
                percent_int = int(
                    percent
                )  # test that the argument can be cast to an integer value
                if percent_int <= 0:
                    stderr(
                        "[font-line] ERROR: Please enter a percent value that is "
                        "greater than zero.")
                    sys.exit(1)
                if percent_int > 100:
                    stdout(
                        "[font-line] Warning: You entered a percent value over 100%. "
                        "Please confirm that this is your intended metrics modification."
                    )
            except ValueError:
                stderr("[font-line] ERROR: You entered '" + percent +
                       "'. This argument needs to be an integer value.")
                sys.exit(1)
            for fontpath in c.argv[2:]:
                if file_exists(fontpath):
                    if is_supported_filetype(fontpath):
                        if modify_linegap_percent(fontpath, percent) is True:
                            outpath = get_linegap_percent_filepath(
                                fontpath, percent)
                            stdout("[font-line] '" + fontpath +
                                   "' successfully modified to '" + outpath +
                                   "'.")
                        else:  # pragma: no cover
                            stderr(
                                "[font-line] ERROR: Unsuccessful modification of '"
                                + fontpath + "'.")
                    else:
                        stderr(
                            "[font-line] ERROR: '" + fontpath +
                            "' does not appear to be a supported font file type."
                        )
                else:
                    stderr("[font-line] ERROR: '" + fontpath +
                           "' does not appear to be a valid filepath.")
    else:
        stderr(
            "[font-lines] ERROR: You used an unsupported argument to the executable. "
            "Please review the `font-line --help` documentation and try again."
        )
        sys.exit(1)
def test_stderr_capsysfail(capsys):    # confirm that capsys capturing standard out appropriately
    stderr("bogus text for a test")
    out, err = capsys.readouterr()
    assert err != "something else"
    assert err == "bogus text for a test\n"
Esempio n. 21
0
def main():
    """Defines the logic for the `font-line` command line executable"""
    c = Command()

    if c.does_not_validate_missing_args():
        stderr("[font-line] ERROR: Please include one or more arguments with your command.")
        sys.exit(1)

    if c.is_help_request():
        stdout(settings.HELP)
        sys.exit(0)
    elif c.is_version_request():
        stdout(settings.VERSION)
        sys.exit(0)
    elif c.is_usage_request():
        stdout(settings.USAGE)
        sys.exit(0)

    # REPORT sub-command
    if c.subcmd == "report":
        if c.argc < 2:
            stderr("[font-line] ERROR: Missing file path argument(s) after the report subcommand.")
            sys.exit(1)
        else:
            for fontpath in c.argv[1:]:
                # test for existence of file on path
                if file_exists(fontpath):
                    # test that filepath includes file of a supported file type
                    if is_supported_filetype(fontpath):
                        stdout(get_font_report(fontpath))
                    else:
                        stderr("[font-line] ERROR: '" + fontpath + "' does not appear to be a supported font file type.")
                else:
                    stderr("[font-line] ERROR: '" + fontpath + "' does not appear to be a valid filepath.")
    # PERCENT sub-command
    elif c.subcmd == "percent":
        if c.argc < 3:
            stderr("[font-line] ERROR: Not enough arguments.")
            sys.exit(1)
        else:
            percent = c.argv[1]
            # test the percent integer argument
            try:
                percent_int = int(percent)  # test that the argument can be cast to an integer value
                if percent_int <= 0:
                    stderr("[font-line] ERROR: Please enter a percent value that is greater than zero.")
                    sys.exit(1)
                if percent_int > 100:
                    stdout("[font-line] Warning: You entered a percent value over 100%. Please confirm that this is "
                           "your intended metrics modification.")
            except ValueError:
                stderr("[font-line] ERROR: You entered '" + percent + "'. This argument needs to be an integer value.")
                sys.exit(1)
            for fontpath in c.argv[2:]:
                if file_exists(fontpath):
                    if is_supported_filetype(fontpath):
                        if modify_linegap_percent(fontpath, percent) is True:
                            outpath = get_linegap_percent_filepath(fontpath, percent)
                            stdout("[font-line] '" + fontpath + "' successfully modified to '" + outpath + "'.")
                        else:  # pragma: no cover
                            stderr("[font-line] ERROR: Unsuccessful modification of '" + fontpath + "'.")
                    else:
                        stderr("[font-line] ERROR: '" + fontpath + "' does not appear to be a supported font file type.")
                else:
                    stderr("[font-line] ERROR: '" + fontpath + "' does not appear to be a valid filepath.")
    else:
        stderr("[font-lines] ERROR: You used an unsupported argument to the executable. Please review the"
               " `font-line --help` documentation and try again.")
        sys.exit(1)
Esempio n. 22
0
def modify_linegap_percent(fontpath, percent):
    try:
        tt = ttLib.TTFont(fontpath)

        # get observed start values from the font
        os2_typo_ascender = tt["OS/2"].sTypoAscender
        os2_typo_descender = tt["OS/2"].sTypoDescender
        os2_typo_linegap = tt["OS/2"].sTypoLineGap
        hhea_ascent = tt["hhea"].ascent
        hhea_descent = tt["hhea"].descent
        units_per_em = tt["head"].unitsPerEm

        # calculate necessary delta values
        os2_typo_ascdesc_delta = os2_typo_ascender + -(os2_typo_descender)
        hhea_ascdesc_delta = hhea_ascent + -(hhea_descent)

        # define percent UPM from command line request
        factor = 1.0 * int(percent) / 100

        # define line spacing units
        line_spacing_units = int(factor * units_per_em)

        # define total height as UPM + line spacing units
        total_height = line_spacing_units + units_per_em

        # height calculations for adjustments
        delta_height = total_height - hhea_ascdesc_delta
        upper_lower_add_units = int(0.5 * delta_height)

        # redefine hhea linegap to 0 in all cases
        hhea_linegap = 0

        # Define metrics based upon original design approach in the font
        # Google metrics approach
        if os2_typo_linegap == 0 and (os2_typo_ascdesc_delta > units_per_em):
            # define values
            os2_typo_ascender += upper_lower_add_units
            os2_typo_descender -= upper_lower_add_units
            hhea_ascent += upper_lower_add_units
            hhea_descent -= upper_lower_add_units
            os2_win_ascent = hhea_ascent
            os2_win_descent = -hhea_descent
        # Adobe metrics approach
        elif os2_typo_linegap == 0 and (os2_typo_ascdesc_delta
                                        == units_per_em):
            hhea_ascent += upper_lower_add_units
            hhea_descent -= upper_lower_add_units
            os2_win_ascent = hhea_ascent
            os2_win_descent = -hhea_descent
        else:
            os2_typo_linegap = line_spacing_units
            hhea_ascent = int(os2_typo_ascender + 0.5 * os2_typo_linegap)
            hhea_descent = -(total_height - hhea_ascent)
            os2_win_ascent = hhea_ascent
            os2_win_descent = -hhea_descent

        # define updated values from above calculations
        tt["hhea"].lineGap = hhea_linegap
        tt["OS/2"].sTypoAscender = os2_typo_ascender
        tt["OS/2"].sTypoDescender = os2_typo_descender
        tt["OS/2"].sTypoLineGap = os2_typo_linegap
        tt["OS/2"].usWinAscent = os2_win_ascent
        tt["OS/2"].usWinDescent = os2_win_descent
        tt["hhea"].ascent = hhea_ascent
        tt["hhea"].descent = hhea_descent

        tt.save(get_linegap_percent_filepath(fontpath, percent))
        return True
    except Exception as e:  # pragma: no cover
        stderr(
            "[font-line] ERROR: Unable to modify the line spacing in the font file '"
            + fontpath + "'. " + str(e))
        sys.exit(1)