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_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
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
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)
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)
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)
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 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)
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"
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 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)