def lint(plain_output: bool) -> int: """ Entry point for `se lint` """ parser = argparse.ArgumentParser(description="Check for various Standard Ebooks style errors.") parser.add_argument("-s", "--skip-lint-ignore", action="store_true", help="ignore rules in se-lint-ignore.xml file") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity") parser.add_argument("directories", metavar="DIRECTORY", nargs="+", help="a Standard Ebooks source directory") args = parser.parse_args() called_from_parallel = se.is_called_from_parallel(False) force_terminal = True if called_from_parallel else None # True will force colors, None will guess whether colors are enabled, False will disable colors first_output = True return_code = 0 # Rich needs to know the terminal width in order to format tables. # If we're called from Parallel, there is no width because Parallel is not a terminal. Thus we must export $COLUMNS before # invoking Parallel, and then get that value here. console = Console(width=int(os.environ["COLUMNS"]) if called_from_parallel and "COLUMNS" in os.environ else None, highlight=False, theme=se.RICH_THEME, force_terminal=force_terminal) # Syntax highlighting will do weird things when printing paths; force_terminal prints colors when called from GNU Parallel for directory in args.directories: directory = Path(directory).resolve() messages = [] exception = None table_data = [] has_output = False try: se_epub = SeEpub(directory) messages = se_epub.lint(args.skip_lint_ignore) except se.SeException as ex: exception = ex if len(args.directories) > 1: return_code = se.LintFailedException.code else: return_code = ex.code # Print a separator newline if more than one table is printed if not first_output and (args.verbose or messages or exception): console.print("") elif first_output: first_output = False # Print the table header if ((len(args.directories) > 1 or called_from_parallel) and (messages or exception)) or args.verbose: has_output = True if plain_output: console.print(directory) else: console.print(f"[reverse][path][link=file://{directory}]{directory}[/][/][/reverse]") if exception: has_output = True se.print_error(exception, plain_output=plain_output) # Print the tables if messages: has_output = True return_code = se.LintFailedException.code if plain_output: for message in messages: label = "[Manual Review]" if message.message_type == se.MESSAGE_TYPE_ERROR: label = "[Error]" # Replace color markup with ` message.text = se.prep_output(message.text, True) message_filename = "" if message.filename: message_filename = message.filename.name console.print(f"{message.code} {label} {message_filename} {message.text}") if message.submessages: for submessage in message.submessages: # Indent each line in case we have a multi-line submessage console.print(regex.sub(r"^", "\t", submessage, flags=regex.MULTILINE)) else: for message in messages: alert = "[bright_yellow]Manual Review[/bright_yellow]" if message.message_type == se.MESSAGE_TYPE_ERROR: alert = "[bright_red]Error[/bright_red]" # Add hyperlinks around message filenames message_filename = "" if message.filename: message_filename = f"[link=file://{message.filename.resolve()}]{message.filename.name}[/link]" table_data.append([message.code, alert, message_filename, message.text]) if message.submessages: for submessage in message.submessages: # Brackets don't need to be escaped in submessages if we instantiate them in Text() submessage_object = Text(submessage, style="dim") table_data.append([" ", " ", Text("→", justify="right"), submessage_object]) table = Table(show_header=True, header_style="bold", show_lines=True, expand=True) table.add_column("Code", width=5, no_wrap=True) table.add_column("Severity", no_wrap=True) table.add_column("File", no_wrap=True) table.add_column("Message", ratio=10) for row in table_data: table.add_row(row[0], row[1], row[2], row[3]) console.print(table) if args.verbose and not messages and not exception: if plain_output: console.print("OK") else: table = Table(show_header=False, box=box.SQUARE) table.add_column("", style="white on green4 bold") table.add_row("OK") console.print(table) # Print a newline if we're called from parallel and we just printed something, to # better visually separate output blocks if called_from_parallel and has_output: console.print("") return return_code
def lint() -> int: """ Entry point for `se lint` """ parser = argparse.ArgumentParser( description="Check for various Standard Ebooks style errors.") parser.add_argument( "-p", "--plain", action="store_true", help="print plain text output, without tables or colors") parser.add_argument("-n", "--no-colors", dest="colors", action="store_false", help="do not use colored output") parser.add_argument("-s", "--skip-lint-ignore", action="store_true", help="ignore rules in se-lint-ignore.xml file") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity") parser.add_argument("directories", metavar="DIRECTORY", nargs="+", help="a Standard Ebooks source directory") args = parser.parse_args() first_output = True return_code = 0 for directory in args.directories: try: se_epub = SeEpub(directory) messages = se_epub.lint(args.skip_lint_ignore) except se.SeException as ex: se.print_error(ex) return ex.code table_data = [] # Print a separator newline if more than one table is printed if not first_output and (args.verbose or messages): print("") elif first_output: first_output = False # Print the table header if args.verbose or (messages and len(args.directories) > 1): if args.plain: print(se_epub.path) else: print(stylize(str(se_epub.path), attr("reverse"))) # Print the table if messages: return_code = se.LintFailedException.code if args.plain: for message in messages: label = "Manual Review:" if message.message_type == se.MESSAGE_TYPE_ERROR: label = "Error:" print( f"{message.code} {label} {message.filename} {message.text}" ) if message.submessages: for submessage in message.submessages: print(f"\t{submessage}") else: table_data.append([ stylize("Code", attr("bold")), stylize("Severity", attr("bold")), stylize("File", attr("bold")), stylize("Message", attr("bold")) ]) for message in messages: alert = "Manual Review" if message.message_type == se.MESSAGE_TYPE_ERROR: alert = "Error" message_text = message.text if args.colors: if message.message_type == se.MESSAGE_TYPE_ERROR: alert = stylize(alert, fg("red")) else: alert = stylize(alert, fg("yellow")) # By convention, any text within the message text that is surrounded in backticks # is rendered in blue message_text = regex.sub( r"`(.+?)`", stylize(r"\1", fg("light_blue")), message_text) table_data.append( [message.code, alert, message.filename, message_text]) if message.submessages: for submessage in message.submessages: table_data.append([" ", " ", "→", f"{submessage}"]) _print_table(table_data, 3) if args.verbose and not messages: if args.plain: print("OK") else: table_data.append([ stylize(" OK ", bg("green") + fg("white") + attr("bold")) ]) _print_table(table_data) return return_code
def lint() -> int: """ Entry point for `se lint` """ from termcolor import colored parser = argparse.ArgumentParser(description="Check for various Standard Ebooks style errors.") parser.add_argument("-p", "--plain", action="store_true", help="print plain output") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity") parser.add_argument("directories", metavar="DIRECTORY", nargs="+", help="a Standard Ebooks source directory") args = parser.parse_args() first_output = True return_code = 0 for directory in args.directories: try: se_epub = SeEpub(directory) except se.SeException as ex: se.print_error(ex) return ex.code messages = se_epub.lint() table_data = [] # Print a separator newline if more than one table is printed if not first_output and (args.verbose or messages): print("") elif first_output: first_output = False # Print the table header if args.verbose or (messages and len(args.directories) > 1): if args.plain: print(se_epub.path) else: print(colored(se_epub.path, "white", attrs=["reverse"])) # Print the table if messages: return_code = se.LintFailedException.code if args.plain: for message in messages: if message.is_submessage: print("\t" + message.text) else: label = "Manual Review:" if message.message_type == se.MESSAGE_TYPE_ERROR: label = "Error:" print(label, message.filename, message.text) else: for message in messages: if message.is_submessage: table_data.append([" ", "→", "{}".format(message.text)]) else: alert = colored("Manual Review", "yellow") if message.message_type == se.MESSAGE_TYPE_ERROR: alert = colored("Error", "red") table_data.append([alert, message.filename, message.text]) se.print_table(table_data, 2) if args.verbose and not messages: if args.plain: print("OK") else: table_data.append([colored("OK", "green", attrs=["reverse"])]) se.print_table(table_data) return return_code
def lint() -> int: """ Entry point for `se lint` """ parser = argparse.ArgumentParser( description="Check for various Standard Ebooks style errors.") parser.add_argument("-n", "--no-colors", dest="colors", action="store_false", help="don’t use color or hyperlinks in output") parser.add_argument( "-p", "--plain", action="store_true", help="print plain text output, without tables or colors") parser.add_argument("-s", "--skip-lint-ignore", action="store_true", help="ignore rules in se-lint-ignore.xml file") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity") parser.add_argument("directories", metavar="DIRECTORY", nargs="+", help="a Standard Ebooks source directory") args = parser.parse_args() called_from_parallel = se.is_called_from_parallel() first_output = True return_code = 0 console = Console( highlight=False, theme=se.RICH_THEME, force_terminal=called_from_parallel ) # Syntax highlighting will do weird things when printing paths; force_terminal prints colors when called from GNU Parallel for directory in args.directories: directory = Path(directory).resolve() messages = [] exception = None table_data = [] has_output = False try: se_epub = SeEpub(directory) messages = se_epub.lint(args.skip_lint_ignore) except se.SeException as ex: exception = ex if len(args.directories) > 1: return_code = se.LintFailedException.code else: return_code = ex.code # Print a separator newline if more than one table is printed if not first_output and (args.verbose or messages or exception): console.print("") elif first_output: first_output = False # Print the table header if ((len(args.directories) > 1 or called_from_parallel) and (messages or exception)) or args.verbose: has_output = True if args.plain: console.print(directory) else: console.print(f"[reverse]{directory}[/reverse]") if exception: has_output = True se.print_error(exception) # Print the tables if messages: has_output = True return_code = se.LintFailedException.code if args.plain: for message in messages: label = "Manual Review:" if message.message_type == se.MESSAGE_TYPE_ERROR: label = "Error:" # Replace color markup with ` message.text = regex.sub( r"\[(?:/|xhtml|xml|val|attr|val|class|path|url|text|bash|link)(?:=[^\]]*?)*\]", "`", message.text) message.text = regex.sub(r"`+", "`", message.text) message_filename = "" if message.filename: message_filename = message.filename.name console.print( f"{message.code} {label} {message_filename} {message.text}" ) if message.submessages: for submessage in message.submessages: # Indent each line in case we have a multi-line submessage console.print( regex.sub(r"^", "\t", submessage, flags=regex.MULTILINE)) else: for message in messages: alert = "Manual Review" if message.message_type == se.MESSAGE_TYPE_ERROR: alert = "Error" message_text = message.text if args.colors: if message.message_type == se.MESSAGE_TYPE_ERROR: alert = f"[bright_red]{alert}[/bright_red]" else: alert = f"[bright_yellow]{alert}[/bright_yellow]" # Add hyperlinks around message filenames message_filename = "" if message.filename: message_filename = f"[link=file://{message.filename.resolve()}]{message.filename.name}[/link]" else: # Replace color markup with ` message_text = regex.sub( r"\[(?:/|xhtml|xml|val|attr|val|class|path|url|text|bash|link)(?:=[^\]]*?)*\]", "`", message_text) message_text = regex.sub(r"`+", "`", message_text) message_filename = "" if message.filename: message_filename = message.filename.name table_data.append( [message.code, alert, message_filename, message_text]) if message.submessages: for submessage in message.submessages: # Brackets don't need to be escaped in submessages if we instantiate them in Text() if args.colors: submessage_object = Text(submessage, style="dim") else: submessage_object = Text(submessage) table_data.append([ " ", " ", Text("→", justify="right"), submessage_object ]) table = Table(show_header=True, header_style="bold", show_lines=True) table.add_column("Code", width=5, no_wrap=True) table.add_column("Severity", no_wrap=True) table.add_column("File", no_wrap=True) table.add_column("Message") for row in table_data: table.add_row(row[0], row[1], row[2], row[3]) console.print(table) if args.verbose and not messages and not exception: if args.plain: console.print("OK") else: table = Table(show_header=False, box=box.SQUARE) table.add_column( "", style="white on green4 bold" if args.colors else None) table.add_row("OK") console.print(table) # Print a newline if we're called from parallel and we just printed something, to # better visually separate output blocks if called_from_parallel and has_output: console.print("") return return_code