def do_prompt(text: str, default: str = None, validator: Callable[[str], Any] = nonempty) -> Union[str, bool]: # NOQA while True: if default is not None: prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) else: prompt = PROMPT_PREFIX + text + ': ' if USE_LIBEDIT: # Note: libedit has a problem for combination of ``input()`` and escape # sequence (see #5335). To avoid the problem, all prompts are not colored # on libedit. pass elif readline: # pass input_mode=True if readline available prompt = colorize(COLOR_QUESTION, prompt, input_mode=True) else: prompt = colorize(COLOR_QUESTION, prompt, input_mode=False) x = term_input(prompt).strip() if default and not x: x = default try: x = validator(x) except ValidationError as err: print(red('* ' + str(err))) continue break return x
def test_warning_location(app, status, warning): logging.setup(app, status, warning) logger = logging.getLogger(__name__) logger.warning('message1', location='index') assert 'index.txt: WARNING: message1' in warning.getvalue() logger.warning('message2', location=('index', 10)) assert 'index.txt:10: WARNING: message2' in warning.getvalue() logger.warning('message3', location=None) assert colorize('darkred', 'WARNING: message3') in warning.getvalue() node = nodes.Node() node.source, node.line = ('index.txt', 10) logger.warning('message4', location=node) assert 'index.txt:10: WARNING: message4' in warning.getvalue() node.source, node.line = ('index.txt', None) logger.warning('message5', location=node) assert 'index.txt:: WARNING: message5' in warning.getvalue() node.source, node.line = (None, 10) logger.warning('message6', location=node) assert '<unknown>:10: WARNING: message6' in warning.getvalue() node.source, node.line = (None, None) logger.warning('message7', location=node) assert colorize('darkred', 'WARNING: message7') in warning.getvalue()
def test_colored_logs(app, status, warning): app.verbosity = 2 logging.setup(app, status, warning) logger = logging.getLogger(__name__) # default colors logger.debug('message1') logger.verbose('message2') logger.info('message3') logger.warning('message4') logger.critical('message5') logger.error('message6') assert colorize('darkgray', 'message1') in status.getvalue() assert 'message2\n' in status.getvalue() # not colored assert 'message3\n' in status.getvalue() # not colored assert colorize('darkred', 'WARNING: message4') in warning.getvalue() assert 'WARNING: message5\n' in warning.getvalue() # not colored assert 'WARNING: message6\n' in warning.getvalue() # not colored # color specification logger.debug('message7', color='white') logger.info('message8', color='red') assert colorize('white', 'message7') in status.getvalue() assert colorize('red', 'message8') in status.getvalue()
def test_warning_location(app, status, warning): logging.setup(app, status, warning) logger = logging.getLogger(__name__) logger.warning('message1', location='index') assert 'index.txt: WARNING: message1' in warning.getvalue() logger.warning('message2', location=('index', 10)) assert 'index.txt:10: WARNING: message2' in warning.getvalue() logger.warning('message3', location=None) assert colorize('darkred', 'WARNING: message3') in warning.getvalue() node = nodes.Node() node.source, node.line = ('index.txt', 10) logger.warning('message4', location=node) assert 'index.txt:10: WARNING: message4' in warning.getvalue() node.source, node.line = ('index.txt', None) logger.warning('message5', location=node) assert 'index.txt:: WARNING: message5' in warning.getvalue() node.source, node.line = (None, 10) logger.warning('message6', location=node) assert '<unknown>:10: WARNING: message6' in warning.getvalue() node.source, node.line = (None, None) logger.warning('message7', location=node) assert colorize('darkred', 'WARNING: message7') in warning.getvalue()
def test_colored_logs(app, status, warning): app.verbosity = 2 logging.setup(app, status, warning) logger = logging.getLogger(__name__) # default colors logger.debug('message1') logger.verbose('message2') logger.info('message3') logger.warning('message4') logger.critical('message5') logger.error('message6') assert colorize('darkgray', 'message1') in status.getvalue() assert 'message2\n' in status.getvalue() # not colored assert 'message3\n' in status.getvalue() # not colored assert colorize('darkred', 'WARNING: message4') in warning.getvalue() assert 'WARNING: message5\n' in warning.getvalue() # not colored assert 'WARNING: message6\n' in warning.getvalue() # not colored # color specification logger.debug('message7', color='white') logger.info('message8', color='red') assert colorize('white', 'message7') in status.getvalue() assert colorize('red', 'message8') in status.getvalue()
def setup_logger(verbose=1, color=True): """ Sets up and returns a Python Logger instance for the Sage documentation builder. The optional argument sets logger's level and message format. """ # Set up colors. Adapted from sphinx.cmdline. import sphinx.util.console as c if not color or not sys.stdout.isatty() or not c.color_terminal(): c.nocolor() # Available colors: black, darkgray, (dark)red, dark(green), # brown, yellow, (dark)blue, purple, fuchsia, turquoise, teal, # lightgray, white. Available styles: reset, bold, faint, # standout, underline, blink. # Set up log record formats. format_std = "%(message)s" formatter = logging.Formatter(format_std) # format_debug = "%(module)s #%(lineno)s %(funcName)s() %(message)s" fields = ["%(module)s", "#%(lineno)s", "%(funcName)s()", "%(message)s"] colors = ["darkblue", "darkred", "brown", "reset"] styles = ["reset", "reset", "reset", "reset"] format_debug = "" for i in xrange(len(fields)): format_debug += c.colorize(styles[i], c.colorize(colors[i], fields[i])) if i != len(fields): format_debug += " " # Documentation: http://docs.python.org/library/logging.html logger = logging.getLogger("doc.common.builder") # Note: There's also Handler.setLevel(). The argument is the # lowest severity message that the respective logger or handler # will pass on. The default levels are DEBUG, INFO, WARNING, # ERROR, and CRITICAL. We use "WARNING" for normal verbosity and # "ERROR" for quiet operation. It's possible to define custom # levels. See the documentation for details. if verbose == 0: logger.setLevel(logging.ERROR) if verbose == 1: logger.setLevel(logging.WARNING) if verbose == 2: logger.setLevel(logging.INFO) if verbose == 3: logger.setLevel(logging.DEBUG) formatter = logging.Formatter(format_debug) handler = logging.StreamHandler() handler.setFormatter(formatter) logger.addHandler(handler) return logger
def setup_logger(verbose=1, color=True): """ Sets up and returns a Python Logger instance for the Sage documentation builder. The optional argument sets logger's level and message format. """ # Set up colors. Adapted from sphinx.cmdline. import sphinx.util.console as c if not color or not sys.stdout.isatty() or not c.color_terminal(): c.nocolor() # Available colors: black, darkgray, (dark)red, dark(green), # brown, yellow, (dark)blue, purple, fuchsia, turquoise, teal, # lightgray, white. Available styles: reset, bold, faint, # standout, underline, blink. # Set up log record formats. format_std = "%(message)s" formatter = logging.Formatter(format_std) # format_debug = "%(module)s #%(lineno)s %(funcName)s() %(message)s" fields = ['%(module)s', '#%(lineno)s', '%(funcName)s()', '%(message)s'] colors = ['darkblue', 'darkred', 'brown', 'reset'] styles = ['reset', 'reset', 'reset', 'reset'] format_debug = "" for i in xrange(len(fields)): format_debug += c.colorize(styles[i], c.colorize(colors[i], fields[i])) if i != len(fields): format_debug += " " # Documentation: http://docs.python.org/library/logging.html logger = logging.getLogger('doc.common.builder') # Note: There's also Handler.setLevel(). The argument is the # lowest severity message that the respective logger or handler # will pass on. The default levels are DEBUG, INFO, WARNING, # ERROR, and CRITICAL. We use "WARNING" for normal verbosity and # "ERROR" for quiet operation. It's possible to define custom # levels. See the documentation for details. if verbose == 0: logger.setLevel(logging.ERROR) if verbose == 1: logger.setLevel(logging.WARNING) if verbose == 2: logger.setLevel(logging.INFO) if verbose == 3: logger.setLevel(logging.DEBUG) formatter = logging.Formatter(format_debug) handler = logging.StreamHandler() handler.setFormatter(formatter) logger.addHandler(handler) return logger
def reformat_pages(app, exception): if exception is not None or not app.site_pages: return minify = app.config["html_theme_options"].get("html_minify", False) last = -1 npages = len(app.site_pages) transform = "Minifying" if minify else "Prettifying" print("{0} {1} files".format(transform, npages)) transform = transform.lower() # TODO: Consider using parallel execution for i, page in enumerate(app.site_pages): if int(100 * (i / npages)) - last >= 1: last = int(100 * (i / npages)) color_page = console.colorize("blue", page) msg = "{0} files... [{1}%] {2}".format(transform, last, color_page) sys.stdout.write("\033[K" + msg + "\r") with open(page, "r", encoding="utf-8") as content: if minify: from css_html_js_minify.html_minifier import html_minify html = html_minify(content.read()) else: soup = BeautifulSoup(content.read(), features="lxml") html = soup.prettify() with open(page, "w", encoding="utf-8") as content: content.write(html) app.site_pages[:] = [] print()
def do_prompt(text, default=None, validator=nonempty): # type: (str, str, Callable[[str], Any]) -> Union[str, bool] while True: if default is not None: prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) else: prompt = PROMPT_PREFIX + text + ': ' if USE_LIBEDIT: # Note: libedit has a problem for combination of ``input()`` and escape # sequence (see #5335). To avoid the problem, all prompts are not colored # on libedit. pass else: prompt = colorize(COLOR_QUESTION, prompt, input_mode=True) x = term_input(prompt).strip() if default and not x: x = default x = term_decode(x) try: x = validator(x) except ValidationError as err: print(red('* ' + str(err))) continue break return x
def do_prompt(text, default=None, validator=nonempty): # type: (unicode, unicode, Callable[[unicode], Any]) -> Union[unicode, bool] while True: if default is not None: prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) # type: unicode else: prompt = PROMPT_PREFIX + text + ': ' if PY2: # for Python 2.x, try to get a Unicode string out of it if prompt.encode('ascii', 'replace').decode('ascii', 'replace') \ != prompt: if TERM_ENCODING: prompt = prompt.encode(TERM_ENCODING) else: print(turquoise('* Note: non-ASCII default value provided ' 'and terminal encoding unknown -- assuming ' 'UTF-8 or Latin-1.')) try: prompt = prompt.encode('utf-8') except UnicodeEncodeError: prompt = prompt.encode('latin1') prompt = colorize('purple', prompt, input_mode=True) x = term_input(prompt).strip() if default and not x: x = default x = term_decode(x) try: x = validator(x) except ValidationError as err: print(red('* ' + str(err))) continue break return x
def generate_tool_documentation(temppath, binpath, tool_directory_path, tool_sub_directory_path): for tool in os.listdir( os.path.join(_TRUNK, tool_directory_path, tool_sub_directory_path)): if tool.startswith('.'): continue if tool == 'CMakeLists.txt': continue log_nonl('generating user documentation... ' + colorize('darkgreen', tool)) usr_rst = os.path.join(_TOOLS, tool_sub_directory_path, tool + '.rst') man_rst = os.path.join(_TOOLS, tool_sub_directory_path, 'man', tool + '.txt') # Writing RST fails if the target path does not exist if not os.path.exists( os.path.join(_TOOLS, tool_sub_directory_path, 'man')): os.makedirs(os.path.join(_TOOLS, tool_sub_directory_path, 'man')) generate_manpage(tool, man_rst, binpath) if os.path.exists(usr_rst): with open(usr_rst, 'r+') as usr_rst_handle: for line in usr_rst_handle: if f'include:: man/{tool}.txt' in line: break else: # not found usr_rst_handle.write(f'\n\n.. include:: man/{tool}.txt\n') elif os.path.exists(man_rst): _LOG.warning( 'No help available for {0}. Only man page will be available.'. format(tool)) open(usr_rst, 'w+').write( '.. index:: {0}\n\n.. _tool-{0}:\n\n{0}\n{1}\n\n.. include:: man/{0}.txt\n' .format(tool, '=' * len(tool))) else: _LOG.warning('No documentation generated for {0}'.format(tool))
def do_prompt(text, default=None, validator=nonempty): # type: (unicode, unicode, Callable[[unicode], Any]) -> Union[unicode, bool] while True: if default is not None: prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) # type: unicode else: prompt = PROMPT_PREFIX + text + ': ' if PY2: # for Python 2.x, try to get a Unicode string out of it if prompt.encode('ascii', 'replace').decode('ascii', 'replace') \ != prompt: if TERM_ENCODING: prompt = prompt.encode(TERM_ENCODING) else: print(turquoise(__('* Note: non-ASCII default value provided ' 'and terminal encoding unknown -- assuming ' 'UTF-8 or Latin-1.'))) try: prompt = prompt.encode('utf-8') except UnicodeEncodeError: prompt = prompt.encode('latin1') prompt = colorize('purple', prompt, input_mode=True) x = term_input(prompt).strip() if default and not x: x = default x = term_decode(x) try: x = validator(x) except ValidationError as err: print(red('* ' + str(err))) continue break return x
def status_iterator(iterable, summary, color="darkgreen", length=0, verbosity=0, stringify_func=display_chunk): # type: (Iterable, unicode, str, int, int, Callable[[Any], unicode]) -> Iterable # NOQA if length == 0: for item in old_status_iterator(iterable, summary, color, stringify_func): yield item return l = 0 summary = bold(summary) for item in iterable: l += 1 s = '%s[%3d%%] %s' % (summary, 100 * l / length, colorize(color, stringify_func(item))) if verbosity: s += '\n' else: s = term_width_line(s) logger.info(s, nonl=True) yield item if l > 0: logger.info('')
def status_iterator(mapping: Mapping[str, str], summary: str, color: str = "darkgreen", length: int = 0, verbosity: int = 0) -> Tuple[str, str]: """ Displays the status of iterating through a Dict/Mapping of strings. Taken from the Sphinx sources. Status includes percent of records in the iterable that have been iterated through. :param mapping: The iterable to iterate through :param summary: A description of the action or operation :param color: The color of the status text; defaults to `darkgreen` :param length: The number of records in the iterable :param verbosity: Flag which writes a newline after each status message :return: A tuple containing the next key-value pair from the iterable """ if length == 0: yield from old_status_iterator(mapping, summary, color) return line_count = 0 summary = bold(summary) for item in mapping.items(): line_count += 1 s = '%s[%3d%%] %s' % (summary, 100 * line_count / length, colorize(color, item[0])) if verbosity: s += '\n' else: s = term_width_line(s) logger.info(s, nonl=True) yield item if line_count > 0: logger.info('')
def status_iterator( iterable: Iterable, summary: str, color: str = "darkgreen", length: int = 0, verbosity: int = 0, stringify_func: Callable[[Any], str] = display_chunk) -> Iterable: if length == 0: yield from old_status_iterator(iterable, summary, color, stringify_func) return l = 0 summary = bold(summary) for item in iterable: l += 1 s = '%s[%3d%%] %s' % (summary, 100 * l / length, colorize(color, stringify_func(item))) if verbosity: s += '\n' else: s = term_width_line(s) logger.info(s, nonl=True) yield item if l > 0: logger.info('')
def do_prompt(text, default=None, validator=nonempty): # type: (unicode, unicode, Callable[[unicode], Any]) -> Union[unicode, bool] while True: if default is not None: prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) # type: unicode else: prompt = PROMPT_PREFIX + text + ': ' if USE_LIBEDIT: # Note: libedit has a problem for combination of ``input()`` and escape # sequence (see #5335). To avoid the problem, all prompts are not colored # on libedit. pass else: prompt = colorize(COLOR_QUESTION, prompt, input_mode=True) x = term_input(prompt).strip() if default and not x: x = default x = term_decode(x) try: x = validator(x) except ValidationError as err: print(red('* ' + str(err))) continue break return x
def format(self, record: logging.LogRecord) -> str: message = super().format(record) color = getattr(record, 'color', None) if color is None: color = COLOR_MAP.get(record.levelno) if color: return colorize(color, message) else: return message
def format(self, record): message = super(ColorizeFormatter, self).format(record) color = getattr(record, 'color', None) if color is None: color = COLOR_MAP.get(record.levelno) if color: return colorize(color, message) else: return message
def format(self, record): # type: (logging.LogRecord) -> str message = super(ColorizeFormatter, self).format(record) color = getattr(record, 'color', None) if color is None: color = COLOR_MAP.get(record.levelno) if color: return colorize(color, message) # type: ignore else: return message
def format(self, record): # type: (logging.LogRecord) -> str message = super(ColorizeFormatter, self).format(record) color = getattr(record, 'color', None) if color is None: color = COLOR_MAP.get(record.levelno) if color: return colorize(color, message) # type: ignore else: return message
def status_iterator(iterable, summary, color="darkgreen", length=0, verbosity=0, stringify_func=display_chunk): # type: (Iterable, str, str, int, int, Callable[[Any], str]) -> Iterable if length == 0: yield from old_status_iterator(iterable, summary, color, stringify_func) return l = 0 summary = bold(summary) for item in iterable: l += 1 s = '%s[%3d%%] %s' % (summary, 100 * l / length, colorize(color, stringify_func(item))) if verbosity: s += '\n' else: s = term_width_line(s) logger.info(s, nonl=True) yield item if l > 0: logger.info('')
def do_prompt(text, default=None, validator=nonempty): # type: (unicode, unicode, Callable[[unicode], Any]) -> Union[unicode, bool] while True: if default is not None: prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default ) # type: unicode else: prompt = PROMPT_PREFIX + text + ': ' if PY2: # for Python 2.x, try to get a Unicode string out of it if prompt.encode('ascii', 'replace').decode('ascii', 'replace') \ != prompt: if TERM_ENCODING: prompt = prompt.encode(TERM_ENCODING) else: print( turquoise( __('* Note: non-ASCII default value provided ' 'and terminal encoding unknown -- assuming ' 'UTF-8 or Latin-1.'))) try: prompt = prompt.encode('utf-8') except UnicodeEncodeError: prompt = prompt.encode('latin1') if USE_LIBEDIT: # Note: libedit has a problem for combination of ``input()`` and escape # sequence (see #5335). To avoid the problem, all prompts are not colored # on libedit. pass else: prompt = colorize(COLOR_QUESTION, prompt, input_mode=True) x = term_input(prompt).strip() if default and not x: x = default x = term_decode(x) try: x = validator(x) except ValidationError as err: print(red('* ' + str(err))) continue break return x
def create_sitemap(app, exception): """Generates the sitemap.xml from the collected HTML page links""" if (not app.config["html_theme_options"].get("site_url", "") or exception is not None or not app.sitemap_links): return filename = app.outdir + "/sitemap.xml" print("Generating sitemap for {0} pages in " "{1}".format(len(app.sitemap_links), console.colorize("blue", filename))) root = ElementTree.Element("urlset") root.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9") for link in app.sitemap_links: url = ElementTree.SubElement(root, "url") ElementTree.SubElement(url, "loc").text = link app.sitemap_links[:] = [] ElementTree.ElementTree(root).write(filename)
def minify_css(app, exception): if exception is not None or not app.config["html_theme_options"].get( "css_minify", False): app.multiprocess_manager.shutdown() return import glob from css_html_js_minify.css_minifier import css_minify css_files = glob.glob(os.path.join(app.outdir, "**", "*.css"), recursive=True) print("Minifying {0} css files".format(len(css_files))) for css_file in css_files: colorized = console.colorize("blue", css_file) msg = "minifying css file {0}".format(colorized) sys.stdout.write("\033[K" + msg + "\r") with open(css_file, "r", encoding="utf-8") as content: css = css_minify(content.read()) with open(css_file, "w", encoding="utf-8") as content: content.write(css) print() app.multiprocess_manager.shutdown()
def log_generated(filename): # log only the last two components of the path (library/file) filename = colorize('darkgreen', str.join('/', filename.split('/')[-2:])) log_nonl(f'transforming Doxygen XML into reST {filename}')
def log_generating_xml(lib_dir, lib_name): lib_name = colorize('darkgreen', lib_name) lib_dir = colorize('darkgray', f'({lib_dir})') log_nonl(f'generating Doxygen XML for library {lib_name} {lib_dir}...')
def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir: str = None) -> None: """Generate project based on values in *d*.""" template = QuickstartRenderer(templatedir=templatedir) if 'mastertoctree' not in d: d['mastertoctree'] = '' if 'mastertocmaxdepth' not in d: d['mastertocmaxdepth'] = 2 d['root_doc'] = d['master'] d['now'] = time.asctime() d['project_underline'] = column_width(d['project']) * '=' d.setdefault('extensions', []) d['copyright'] = time.strftime('%Y') + ', ' + d['author'] d["path"] = os.path.abspath(d['path']) ensuredir(d['path']) srcdir = path.join(d['path'], 'source') if d['sep'] else d['path'] ensuredir(srcdir) if d['sep']: builddir = path.join(d['path'], 'build') d['exclude_patterns'] = '' else: builddir = path.join(srcdir, d['dot'] + 'build') exclude_patterns = map(repr, [ d['dot'] + 'build', 'Thumbs.db', '.DS_Store', ]) d['exclude_patterns'] = ', '.join(exclude_patterns) ensuredir(builddir) ensuredir(path.join(srcdir, d['dot'] + 'templates')) ensuredir(path.join(srcdir, d['dot'] + 'static')) def write_file(fpath: str, content: str, newline: str = None) -> None: if overwrite or not path.isfile(fpath): if 'quiet' not in d: print(__('Creating file %s.') % fpath) with open(fpath, 'wt', encoding='utf-8', newline=newline) as f: f.write(content) else: if 'quiet' not in d: print(__('File %s already exists, skipping.') % fpath) conf_path = os.path.join(templatedir, 'conf.py_t') if templatedir else None if not conf_path or not path.isfile(conf_path): conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py_t') with open(conf_path) as f: conf_text = f.read() write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d)) masterfile = path.join(srcdir, d['master'] + d['suffix']) if template._has_custom_template('quickstart/master_doc.rst_t'): msg = ( 'A custom template `master_doc.rst_t` found. It has been renamed to ' '`root_doc.rst_t`. Please rename it on your project too.') print(colorize('red', msg)) # RemovedInSphinx60Warning write_file(masterfile, template.render('quickstart/master_doc.rst_t', d)) else: write_file(masterfile, template.render('quickstart/root_doc.rst_t', d)) if d.get('make_mode') is True: makefile_template = 'quickstart/Makefile.new_t' batchfile_template = 'quickstart/make.bat.new_t' else: makefile_template = 'quickstart/Makefile_t' batchfile_template = 'quickstart/make.bat_t' if d['makefile'] is True: d['rsrcdir'] = 'source' if d['sep'] else '.' d['rbuilddir'] = 'build' if d['sep'] else d['dot'] + 'build' # use binary mode, to avoid writing \r\n on Windows write_file(path.join(d['path'], 'Makefile'), template.render(makefile_template, d), '\n') if d['batchfile'] is True: d['rsrcdir'] = 'source' if d['sep'] else '.' d['rbuilddir'] = 'build' if d['sep'] else d['dot'] + 'build' write_file(path.join(d['path'], 'make.bat'), template.render(batchfile_template, d), '\r\n') if silent: return print() print( bold(__('Finished: An initial directory structure has been created.'))) print() print(__( 'You should now populate your master file %s and create other documentation\n' 'source files. ') % masterfile, end='') if d['makefile'] or d['batchfile']: print( __('Use the Makefile to build the docs, like so:\n' ' make builder')) else: print( __('Use the sphinx-build command to build the docs, like so:\n' ' sphinx-build -b builder %s %s') % (srcdir, builddir)) print( __('where "builder" is one of the supported builders, ' 'e.g. html, latex or linkcheck.')) print()
def log_generating_pdf(lib_dir, lib_name): lib_name = colorize('darkgreen', lib_name) lib_dir = colorize('darkgray', f'({lib_dir})') log_nonl(f'compiling LaTeX documents for library {lib_name} {lib_dir}...')