def run_suite(): global passed global failed global num_skipped global expectations passed = 0 failed = 0 num_skipped = 0 expectations = 0 start_time = time.time() walk(join(REPO_DIR, 'clox', 'test', 'lox'), run_script) time_passed = time.time() - start_time term.print_line() print() if failed == 0: print('All {} tests passed ({} expectations) in {:.2f} seconds.'.format( term.green(passed), str(expectations), time_passed)) else: print('{} tests passed and {} tests failed in {:.2f} seconds.'.format( term.green(passed), term.red(failed), time_passed)) return failed == 0
def run_suite(name): global interpreter global passed global failed global num_skipped global expectations interpreter = INTERPRETERS[name] passed = 0 failed = 0 num_skipped = 0 expectations = 0 walk(join(REPO_DIR, 'test'), run_script) term.print_line() if failed == 0: print('All {} tests passed ({} expectations).'.format( term.green(passed), str(expectations))) else: print('{} tests passed. {} tests failed.'.format( term.green(passed), term.red(failed))) return failed == 0
def _get_attrib(self, attr, convert_to_str=False): """ Given an attribute name, looks it up on the entry. Names that start with ``tags.`` are looked up in the ``tags`` dictionary. :param attr: Name of attribute to look up. :type attr: ``str`` :param convert_to_str: Convert result to a string. :type convert_to_str: ``bool`` :rtype: ``object`` """ if attr.startswith('tags.'): tag = attr[len('tags.'):] if tag in self.tags and self.tags[tag] != '': return self.tags[tag] elif convert_to_str is True: return '<not set>' else: return self.tags.get(tag) elif not hasattr(self, attr): raise AttributeError('Invalid attribute: {0}. Perhaps you meant ' '{1}?'.format(red(attr), green('tags.' + attr))) else: result = getattr(self, attr) if convert_to_str is True and not result: return '<none>' elif convert_to_str is True and isinstance(result, list): return ', '.join(result) elif convert_to_str is True: return str(result) else: return result
def render(self) -> str: guess = self.guess if self.is_filled() else ' ' assert guess is not None if self.status is Status.PENCILLED_IN: guess = term.dim(guess) elif self.status is Status.MARKED_WRONG: guess = term.red(guess) elif self.status is Status.MARKED_RIGHT: guess = term.green(guess) elif self.status is Status.REVEALED: guess = term.blue(guess) return f' {guess} '
def run_script(path): if "benchmark" in path: return global passed global failed global num_skipped if (splitext(path)[1] != '.lox'): return # Check if we are just running a subset of the tests. if filter_path: this_test = relpath(path, join(REPO_DIR, 'test')) if not this_test.startswith(filter_path): return # Make a nice short path relative to the working directory. # Normalize it to use "/" since, among other things, the interpreters expect # the argument to use that. path = relpath(path).replace("\\", "/") # Update the status line. term.print_line('Passed: {} Failed: {} Skipped: {} {}'.format( term.green(passed), term.red(failed), term.yellow(num_skipped), term.gray('({})'.format(path)))) # Read the test and parse out the expectations. test = Test(path) if not test.parse(): # It's a skipped or non-test file. return test.run() # Display the results. if len(test.failures) == 0: passed += 1 else: failed += 1 term.print_line(term.red('FAIL') + ': ' + path) print('') for failure in test.failures: print(' ' + term.pink(failure)) print('')
def render_entries(cls, entries, additional_columns=None, only_show=None, numbers=False): """ Pretty-prints a list of entries. If the window is wide enough to support printing as a table, runs the `print_table.render_table` function on the table. Otherwise, constructs a line-by-line representation.. :param entries: A list of entries. :type entries: [:py:class:`HostEntry`] :param additional_columns: Columns to show in addition to defaults. :type additional_columns: ``list`` of ``str`` :param only_show: A specific list of columns to show. :type only_show: ``NoneType`` or ``list`` of ``str`` :param numbers: Whether to include a number column. :type numbers: ``bool`` :return: A pretty-printed string. :rtype: ``str`` """ additional_columns = additional_columns or [] if only_show is not None: columns = _uniquify(only_show) else: columns = _uniquify(cls.DEFAULT_COLUMNS + additional_columns) top_row = map(cls.prettyname, columns) table = [top_row] if numbers is False else [[''] + top_row] for i, entry in enumerate(entries): row = [entry._get_attrib(c, convert_to_str=True) for c in columns] table.append(row if numbers is False else [i] + row) cur_width = get_current_terminal_width() colors = [get_color_hash(c, 100, 150) for c in columns] if cur_width >= get_table_width(table): return render_table(table, column_colors=colors if numbers is False else [green] + colors) else: result = [] first_index = 1 if numbers is True else 0 for row in table[1:]: rep = [green('%s:' % row[0] if numbers is True else '-----')] for i, val in enumerate(row[first_index:]): color = colors[i-1 if numbers is True else i] name = columns[i] rep.append(' %s: %s' % (name, color(val))) result.append('\n'.join(rep)) return '\n'.join(result)
def build_sass(skip_up_to_date): '''Process each SASS file.''' imports_mod = None for source in glob.iglob("asset/sass/*.scss"): import_mod = os.path.getmtime(source) if not imports_mod: imports_mod = import_mod imports_mod = max(imports_mod, import_mod) for source in glob.iglob("asset/*.scss"): dest = "site/" + os.path.basename(source).split(".")[0] + ".css" if skip_up_to_date: source_mod = max(os.path.getmtime(source), imports_mod) dest_mod = os.path.getmtime(dest) if source_mod < dest_mod: continue subprocess.call(['sass', source, dest]) print("{} {}".format(term.green("•"), source))
for snippet_name in snippets: snippet = source_code.snippet_tags[chapter][snippet_name] split_chapters.split_chapter(chapter, snippet) build_name = "{}-{:02}-{}".format(chapter_dir, snippet.index, snippet_name) snippet_dir = "{:02}-{}".format(snippet.index, snippet_name) source_dir = os.path.join("gen", "snippets", chapter_dir, snippet_dir) args = [ "make", "-f", "util/c.make", "NAME=" + build_name, "MODE=release", "SOURCE_DIR=" + source_dir, "SNIPPET=true" ] proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() if proc.returncode != 0: print("{} {} / {}".format(term.red("FAIL"), chapter, snippet_name)) print(out.decode('utf-8')) print(err.decode('utf-8')) print() all_passed = False else: print("{} {} / {}".format(term.green("PASS"), chapter, snippet_name)) if not all_passed: sys.exit(1)
def print_tb(tb, nlines=5, ncols=80): """Pretty print the traceback TB. NLINES of Python source lines are displayed. All output lines are fitted within NCOLS column.""" f = tb.tb_frame lineno = tb.tb_lineno co = f.f_code filename = co.co_filename name = co.co_name # display frame header name_str = term.blue(name, True) filename_str = term.green(filename) _print('----', name_str, filename_str) # display source lines linecache.checkcache(filename) errline = '' for n in range(lineno - nlines + 1, lineno + 1): line = linecache.getline(filename, n, f.f_globals).rstrip() if line is not None: lineno_str = term.gray('{:5} '.format(n)) _print(lineno_str, end='') if n == lineno: line_str = term.red(line) errline = line else: line_str = term.reset(line) _print(line_str) def _by_location(key): pos = errline.find(key) if 0 <= pos <= 255: # keys matching the error line come first return chr(pos) elif key.startswith('__'): # keys starting with __ come last return '~' + key else: # sorted in the alphabetical order return key # dump all local variables in the frame keys = sorted(f.f_locals.keys(), key=_by_location) for key in keys: key_str = term.yellow('{:>20}'.format(key)) if key in set([ 'linecache', 'pdb', 'sys', 'os', 're', 'term', 'traceback', '__builtins__' ]): _print(key_str, '= ...') continue else: val_str = trimmed_str(repr(f.f_locals[key]), ncols - 20) _print(key_str, '=', val_str) # dump all attributes for objects attr = getattr(f.f_locals[key], '__dict__', None) if attr: keys = sorted(attr.keys(), key=_by_location) for key in keys: key_str = term.cyan('{:>28}'.format(key)) val_str = trimmed_str(repr(attr[key]), ncols - 28) _print(key_str, val_str)
def format_file(path, skip_up_to_date, dependencies_mod): basename = os.path.basename(path) basename = basename.split('.')[0] output_path = "site/" + basename + ".html" # See if the HTML is up to date. if skip_up_to_date: source_mod = max(os.path.getmtime(path), dependencies_mod) dest_mod = os.path.getmtime(output_path) if source_mod < dest_mod: return title = '' title_html = '' part = None template_file = 'page' errors = [] sections = [] header_index = 0 subheader_index = 0 has_challenges = False design_note = None snippets = None # Read the markdown file and preprocess it. contents = '' with open(path, 'r') as input: # Read each line, preprocessing the special codes. for line in input: stripped = line.lstrip() indentation = line[:len(line) - len(stripped)] if line.startswith('^'): command, _, arg = stripped.rstrip('\n').lstrip('^').partition( ' ') arg = arg.strip() if command == 'title': title = arg title_html = title # Remove any discretionary hyphens from the title. title = title.replace('­', '') # Load the code snippets now that we know the title. snippets = source_code.find_all(title) # If there were any errors loading the code, include them. if title in book.CODE_CHAPTERS: errors.extend(source_code.errors[title]) elif command == 'part': part = arg elif command == 'template': template_file = arg elif command == 'code': contents = insert_snippet(snippets, arg, contents, errors) else: raise Exception('Unknown command "^{} {}"'.format( command, arg)) elif stripped.startswith('## Challenges'): has_challenges = True contents += '<h2><a href="#challenges" name="challenges">Challenges</a></h2>\n' elif stripped.startswith('## Design Note:'): has_design_note = True design_note = stripped[len('## Design Note:') + 1:] contents += '<h2><a href="#design-note" name="design-note">Design Note: {}</a></h2>\n'.format( design_note) elif stripped.startswith('# ') or stripped.startswith( '## ') or stripped.startswith('### '): # Build the section navigation from the headers. index = stripped.find(" ") header_type = stripped[:index] header = pretty(stripped[index:].strip()) anchor = book.get_file_name(header) anchor = re.sub(r'[.?!:/"]', '', anchor) # Add an anchor to the header. contents += indentation + header_type if len(header_type) == 2: header_index += 1 subheader_index = 0 page_number = book.chapter_number(title) number = '{0} . {1}'.format( page_number, header_index) elif len(header_type) == 3: subheader_index += 1 page_number = book.chapter_number(title) number = '{0} . {1} . {2}'.format( page_number, header_index, subheader_index) header_line = '<a href="#{0}" name="{0}"><small>{1}</small> {2}</a>\n'.format( anchor, number, header) contents += header_line # Build the section navigation. if len(header_type) == 2: sections.append([header_index, header]) else: contents += pretty(line) # Validate that every snippet for the chapter is included. for name, snippet in snippets.items(): if name != 'not-yet' and name != 'omit' and snippet != False: errors.append("Unused snippet {}".format(name)) # Show any errors at the top of the file. if errors: error_markdown = "" for error in errors: error_markdown += "**Error: {}**\n\n".format(error) contents = error_markdown + contents # Fix up em dashes. We do this on the entire contents instead of in pretty() # so that we can handle surrounding whitespace even when the "--" is at the # beginning of end of a line in Markdown. contents = EM_DASH_PATTERN.sub('<span class="em">—</span>', contents) # Allow processing markdown inside some tags. contents = contents.replace('<aside', '<aside markdown="1"') contents = contents.replace('<div class="challenges">', '<div class="challenges" markdown="1">') contents = contents.replace('<div class="design-note">', '<div class="design-note" markdown="1">') body = markdown.markdown(contents, extensions=['extra', 'codehilite', 'smarty']) # Turn aside markers in code into spans. In the empty span case, insert a # zero-width space because Chrome seems to lose the span's position if it has # no content. # <span class="c1">// [repl]</span> body = ASIDE_COMMENT_PATTERN.sub(r'<span name="\1">​</span>', body) body = ASIDE_WITH_COMMENT_PATTERN.sub( r'<span class="c1" name="\2">// \1</span>', body) up = 'Table of Contents' if part: up = part elif title == 'Table of Contents': up = 'Crafting Interpreters' data = { 'title': title, 'part': part, 'body': body, 'sections': sections, 'chapters': get_part_chapters(title), 'design_note': design_note, 'has_challenges': has_challenges, 'number': book.chapter_number(title), 'prev': book.adjacent_page(title, -1), 'prev_type': book.adjacent_type(title, -1), 'next': book.adjacent_page(title, 1), 'next_type': book.adjacent_type(title, 1), 'up': up, 'toc': book.TOC } template = environment.get_template(template_file + '.html') output = template.render(data) # Write the output. with codecs.open(output_path, "w", encoding="utf-8") as out: out.write(output) global total_words global num_chapters global empty_chapters word_count = len(contents.split(None)) num = book.chapter_number(title) if num: num = '{}. '.format(num) # Non-chapter pages aren't counted like regular chapters. if part: num_chapters += 1 if word_count < 50: empty_chapters += 1 print(" " + term.gray("{}{}".format(num, title))) elif part != "Backmatter" and word_count < 2000: empty_chapters += 1 print(" {} {}{} ({} words)".format(term.yellow("-"), num, title, word_count)) else: total_words += word_count print(" {} {}{} ({} words)".format(term.green("✓"), num, title, word_count)) elif title in ["Crafting Interpreters", "Table of Contents"]: print("{} {}{}".format(term.green("•"), num, title)) else: if word_count < 50: print(" " + term.gray("{}{}".format(num, title))) else: print("{} {}{} ({} words)".format(term.green("✓"), num, title, word_count))