def test_text_flow(): assert text_flow("") == "" assert text_flow("Testing") == "Testing" assert text_flow("One Two Three") == "One Two Three" assert text_flow("One Two Three", width=5) == ("One\n" "Two\n" "Three") assert text_flow("One Two Three", width=6, space_padding=True) == ("One \n" "Two \n" "Three ") assert text_flow("One Two Three", width=7, space_padding=True) == ("One Two\n" "Three ") assert text_flow("One Two Three", width=9, left_margin=2, space_padding=True) == (" One Two\n" " Three ") assert text_flow("One Two Three", width=7, left_margin=1, space_padding=True) == (" One \n" " Two \n" " Three ")
def render_rationale(self, check, checkid): if not "rationale" in check: return "" # Ideally we'll at some point invoke a proper markdown # parser here. But for now, let's simply fill the raw # content into an 80-column block of text and output it # enclosed in <pre></pre> tags... import html from fontbakery.utils import text_flow, unindent_rationale content = unindent_rationale(check['rationale'], checkid) rationale = html.escape(text_flow(content, 80)) return f"<pre>--- Rationale ---\n{rationale}</pre>\n"
def _render_event_sync(self, print, event): status, message, (section, check, iterargs) = event if not status.weight >= self._structure_threshold \ or status in self._skip_status_report: return if status == START: text = super()._render_event(event) if text: self.stdout.write(text) if status == STARTCHECK: if self.runner: formatted_iterargs = tuple( ('{}[{}]'.format(*item), self.runner.get_iterarg(*item)) for item in iterargs) else: formatted_iterargs = iterargs if self.succinct: with_string = "All fonts" if formatted_iterargs != (): with_string = os.path.basename( f"{formatted_iterargs[0][1]}") print((" >> Check: {}\n" " Desc: {}\n" " Files: {}").format( self.theme["check-id"](check.id), self.theme["description"](check.description), with_string)) else: # Omit printing of iterargs when there's none of them: with_string = "" if formatted_iterargs != (): with_string = f"with {formatted_iterargs[0][1]}" print((' >> {}\n' ' {}\n' ' {}\n').format( self.theme["check-id"](check.id), self.theme["description"](check.description), with_string)) if check.rationale: from fontbakery.utils import text_flow, unindent_rationale content = unindent_rationale(check.rationale).strip() print(' ' + self.theme["rationale-title"](" Rationale:" + " " * 64) + '\n' + text_flow(content, width=76, indent=4, left_margin=2, space_padding=True, text_color=self.theme["rationale-text"])) # Log statuses have weights >= 0 # log_statuses = (INFO, WARN, PASS, SKIP, FAIL, ERROR, DEBUG) if status.weight >= self._log_threshold: print(' * {}: {}'.format(formatStatus(self.theme, status), message)) if hasattr(message, 'traceback'): print(' ', '\n '.join(message.traceback.split('\n'))) if status == ENDCHECK: if not self.succinct: print('\n') print(' Result: {}\n'.format(formatStatus(self.theme, message))) if status == SECTIONSUMMARY: order, counter = message print('') print('=' * 8, f'Section results: {section}', '=' * 8) print('{} {} in section'.format( len(order), len(order) == 1 and 'check' or 'checks')) print('') print(_render_results_counter(self.theme, counter)) if status == END: print('') if self.results_by: print('Collected results by', self.results_by) for key in self._collected_results: if self.results_by == '*check': val = key elif key is not None and self.runner: val = self.runner.get_iterarg(self.results_by, key) elif key is not None: val = key else: val = f'(not using "{self.results_by}")' print(f'{self.results_by}: {val}') print( _render_results_counter(self.theme, self._collected_results[key])) print('') print('Total:') print('') print(_render_results_counter(self.theme, message)) print('') # same end message as parent text = super()._render_event(event) if text: print(text) print( f" {self.theme['header']('Meaning of check results:')}\n" f"\n" f" An {formatStatus(self.theme, 'ERROR')} is something" f" wrong with FontBakery itself, possibly a bug.\n" f" A {formatStatus(self.theme, 'FAIL')} is a problem" f" with the font that must be fixed.\n" f" A {formatStatus(self.theme, 'WARN')} is something" f" that you should consider addressing.\n" f" An {formatStatus(self.theme, 'INFO')} result simply" f" prints something useful. Typically stats.\n" f" A {formatStatus(self.theme, 'PASS')} means the font looks good" f" for the given checking routine.\n" f" And a {formatStatus(self.theme, 'SKIP')} happens when the check" f" does not apply to the given font.\n" f"\n" f" If you get {formatStatus(self.theme, 'ERROR')}s," f" please help us improve the tool by reporting them at\n" f" {self.theme['url']('https://github.com/googlefonts/fontbakery/issues')}\n" f"\n" f" (but other kinds of bug reports and/or\n" f" feature requests are also always welcome, of course!)\n" ) if status not in statuses: print('-' * 8, status, '-' * 8)
def _render_event_sync(self, print, event): status, message, (section, check, iterargs) = event if not status.weight >= self._structure_threshold \ or status in self._skip_status_report: return if status == START: text = super(TerminalReporter, self)._render_event(event) if text: self.stdout.write(text) if status == STARTSECTION: order = message print('='*8, str(section),'='*8) print('{} {} in section'.format(len(order) , len(order) == 1 and 'check' or 'checks' )) print('') if status == STARTCHECK: if self.runner: formatted_iterargs = tuple( ('{}[{}]'.format(*item), self.runner.get_iterarg(*item)) for item in iterargs) else: formatted_iterargs = iterargs # Omit printing of iterargs when there's none of them: with_string = "" if formatted_iterargs != (): with_string = f"with {formatted_iterargs[0][1]}" print((' >> {}\n' ' {}\n' ' {}\n').format( self.theme["check-id"](check.id), self.theme["description"](check.description), with_string)) if check.rationale: from fontbakery.utils import text_flow, unindent_rationale content = unindent_rationale(check.rationale).strip() print(' ' + self.theme["rationale-title"](" Rationale:" + " " * 64) + '\n' + text_flow(content, width=76, indent=4, left_margin=2, space_padding=True, text_color=self.theme["rationale-text"])) # Log statuses have weights >= 0 # log_statuses = (INFO, WARN, PASS, SKIP, FAIL, ERROR, DEBUG) if status.weight >= self._log_threshold: print(' * {}: {}'.format(formatStatus(self.theme, status), message)) if hasattr(message, 'traceback'): print(' ','\n '.join(message.traceback.split('\n'))) if status == ENDCHECK: print('\n Result: {}\n'.format(formatStatus(self.theme, message))) if status == ENDSECTION: print('') print('Section results:') print('') print(_render_results_counter(self.theme, message)) print('') print ('='*8, f'END {section}','='*8) if status == END: print('') if self.results_by: print('Collected results by', self.results_by) for key in self._collected_results: if self.results_by == '*check': val = key elif key is not None and self.runner: val = self.runner.get_iterarg(self.results_by, key) elif key is not None: val = key else: val = f'(not using "{self.results_by}")' print(f'{self.results_by}: {val}') print(_render_results_counter(self.theme, self._collected_results[key])) print('') print('Total:') print('') print(_render_results_counter(self.theme, message)) print('') # same end message as parent text = super(TerminalReporter, self)._render_event(event) if text: print(text) if status not in statuses: print('-'*8, status , '-'*8)