def test_filename_sequence(self): with tempfile.TemporaryDirectory() as tmpdir: with silent(), treelog.HtmlLog(tmpdir) as log: pass self.assertTrue(os.path.exists(os.path.join(tmpdir, 'log.html'))) with silent(), treelog.HtmlLog(tmpdir) as log: pass self.assertTrue(os.path.exists(os.path.join(tmpdir, 'log-1.html'))) with silent(), treelog.HtmlLog(tmpdir) as log: pass self.assertTrue(os.path.exists(os.path.join(tmpdir, 'log-2.html')))
def test_remove_on_failure(self): with tempfile.TemporaryDirectory() as tmpdir: with silent(), treelog.HtmlLog(tmpdir) as log, self.assertRaises( RuntimeError): with log.open('dat', 'wb', level=treelog.proto.Level.info) as f: f.write(b'test') raise RuntimeError self.assertEqual(len(os.listdir(tmpdir)), 3)
def output_tester(self): with tempfile.TemporaryDirectory() as tmpdir: tests = [ 'b444ac06613fc8d63795be9ad0beaf55011936ac.dat', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f.dat', '3ebfa301dc59196f18593c45e519287a23297589.dat', '1ff2b3704aede04eecb51e50ca698efd50a1379b.dat' ] with self.assertSilent(), treelog.HtmlLog(tmpdir, title='test') as htmllog: yield htmllog self.assertEqual(htmllog.filename, 'log.html') self.assertGreater(set(os.listdir(tmpdir)), {'log.html', *tests}) with open(os.path.join(tmpdir, 'log.html'), 'r') as f: lines = f.readlines() self.assertIn('<body>\n', lines) self.assertEqual(lines[lines.index('<body>\n'):], [ '<body>\n', '<div id="header"><div id="bar"><div id="text"><div id="title">test</div></div></div></div>\n', '<div id="log">\n', '<div class="item" data-loglevel="2">my message</div>\n', '<div class="item" data-loglevel="1"><a href="b444ac06613fc8d63795be9ad0beaf55011936ac.dat" download="test.dat">test.dat</a></div>\n', '<div class="context"><div class="title">my context</div><div class="children">\n', '<div class="context"><div class="title">iter 1</div><div class="children">\n', '<div class="item" data-loglevel="1">a</div>\n', '</div><div class="end"></div></div>\n', '<div class="context"><div class="title">iter 2</div><div class="children">\n', '<div class="item" data-loglevel="1">b</div>\n', '</div><div class="end"></div></div>\n', '<div class="context"><div class="title">iter 3</div><div class="children">\n', '<div class="item" data-loglevel="1">c</div>\n', '</div><div class="end"></div></div>\n', '<div class="item" data-loglevel="4">multiple..\n', ' ..lines</div>\n', '<div class="item" data-loglevel="1">generating</div>\n', '<div class="item" data-loglevel="2"><a href="109f4b3c50d7b0df729d299bc6f8e9ef9066971f.dat" download="test.dat">test.dat</a></div>\n', '</div><div class="end"></div></div>\n', '<div class="context"><div class="title">generate_test</div><div class="children">\n', '<div class="item" data-loglevel="3"><a href="3ebfa301dc59196f18593c45e519287a23297589.dat" download="test.dat">test.dat</a></div>\n', '</div><div class="end"></div></div>\n', '<div class="context"><div class="title">context step=0</div><div ' 'class="children">\n', '<div class="item" data-loglevel="1">foo</div>\n', '</div><div class="end"></div></div>\n', '<div class="context"><div class="title">context step=1</div><div ' 'class="children">\n', '<div class="item" data-loglevel="1">bar</div>\n', '</div><div class="end"></div></div>\n', '<div class="item" data-loglevel="4"><a href="3ebfa301dc59196f18593c45e519287a23297589.dat" download="same.dat">same.dat</a></div>\n', '<div class="item" data-loglevel="0"><a href="1ff2b3704aede04eecb51e50ca698efd50a1379b.dat" download="dbg.dat">dbg.dat</a></div>\n', '<div class="item" data-loglevel="0">dbg</div>\n', '<div class="item" data-loglevel="3">warn</div>\n', '</div></body></html>\n' ]) for i, test in enumerate(tests, 1): with open(os.path.join(tmpdir, test), 'rb') as f: self.assertEqual(f.read(), b'test%i' % i)
def test_move_outdir(self): with tempfile.TemporaryDirectory() as tmpdir: outdira = os.path.join(tmpdir, 'a') outdirb = os.path.join(tmpdir, 'b') with silent(), treelog.HtmlLog(outdira) as log: os.rename(outdira, outdirb) os.mkdir(outdira) with log.open('dat', 'wb', level=treelog.proto.Level.info) as f: pass self.assertIn('da39a3ee5e6b4b0d3255bfef95601890afd80709', os.listdir(outdirb))
def _htmllog(outdir, scriptname, kwargs): htmllog = treelog.HtmlLog( outdir, title=scriptname, htmltitle='<a href="http://www.nutils.org">{}</a> {}'.format( SVGLOGO, html.escape(scriptname)), favicon=FAVICON) if kwargs: htmllog.write( '<ul style="list-style-position: inside; padding-left: 0px; margin-top: 0px;">{}</ul>' .format(''.join( '<li>{}={} <span style="color: gray;">{}</span></li>'.format( name, value, doc) for name, value, doc in kwargs)), level=Level.info, escape=False) return htmllog
def call(func, kwargs, scriptname, funcname=None): '''set up compute environment and call function''' outdir = config.outdir or os.path.join( os.path.expanduser(config.outrootdir), scriptname) with contextlib.ExitStack() as stack: stack.enter_context( cache.enable(os.path.join(outdir, config.cachedir)) if config. cache else cache.disable()) stack.enter_context(matrix.backend(config.matrix)) stack.enter_context( log.set( log.FilterLog(log.RichOutputLog() if config.richoutput else log.StdoutLog(), minlevel=5 - config.verbose))) if config.htmloutput: html = stack.enter_context( log.HtmlLog( outdir, title=scriptname, htmltitle='<a href="http://www.nutils.org">{}</a> {}'. format(SVGLOGO, scriptname), favicon=FAVICON)) uri = (config.outrooturi.rstrip('/') + '/' + scriptname if config.outrooturi else pathlib.Path( outdir).resolve().as_uri()) + '/' + html.filename if config.richoutput: t0 = time.perf_counter() bar = lambda running: '{0} [{1}] {2[0]}:{2[1]:02d}:{2[2]:02d}'.format( uri, 'RUNNING' if running else 'STOPPED', _hms(time.perf_counter() - t0)) stack.enter_context(stickybar.activate(bar, update=1)) else: log.info('opened log at', uri) html.write( '<ul style="list-style-position: inside; padding-left: 0px; margin-top: 0px;">{}</ul>' .format(''.join( '<li>{}={} <span style="color: gray;">{}</span></li>'. format(param.name, kwargs.get(param.name, param.default), param.annotation) for param in inspect.signature(func).parameters.values())), level=1, escape=False) stack.enter_context(log.add(html)) stack.enter_context(warnings.via(log.warning)) stack.callback(signal.signal, signal.SIGINT, signal.signal(signal.SIGINT, _sigint_handler)) log.info('nutils v{}'.format(_version())) log.info('start', time.ctime()) try: func(**kwargs) except (KeyboardInterrupt, SystemExit, pdb.bdb.BdbQuit): log.error('killed by user') return 1 except: log.error(traceback.format_exc()) if config.pdb: print( _mkbox('YOUR PROGRAM HAS DIED. The Python debugger', 'allows you to examine its post-mortem state', 'to figure out why this happened. Type "h"', 'for an overview of commands to get going.')) pdb.post_mortem() return 2 else: log.info('finish', time.ctime()) return 0
def create_log(app, env, node, contnode): logger = sphinx.util.logging.getLogger(__name__) if node['reftype'] == 'nutils-log': script = node.get('script') scriptname = str(script.relative_to(project_root)) cmdline_args = node['reftarget'] cmdline = ' '.join(map(shlex.quote, [scriptname, *cmdline_args])) target = '_logs/{}/index'.format( urllib.parse.quote(cmdline, safe='').replace('%', '+')) dst_log = (pathlib.Path(app.builder.outdir) / target).parent if dst_log.exists( ) and dst_log.stat().st_mtime > script.stat().st_mtime: logger.debug( 'Skip building log of {cmdline} because it already exists and ' 'is newer than {script}. Please touch {script} to force a rebuild.' .format(script=scriptname, cmdline=cmdline)) else: if dst_log.exists(): logger.debug('purging old log files... {}'.format(dst_log)) shutil.rmtree(str(dst_log)) else: dst_log.parent.mkdir(parents=True, exist_ok=True) logger.info('creating log... {}'.format(cmdline)) script_dict = runpy.run_path(str(script), run_name='__log_builder__') # Parse cmdline. params = inspect.signature(script_dict['main']).parameters.values() kwargs = {param.name: param.default for param in params} for arg in cmdline_args: if not arg: continue name, sep, value = arg.lstrip('-').partition('=') if not sep: value = not name.startswith('no') if not value: name = name[2:] if name not in kwargs: logger.error('unkown argument {!r}'.format(name)) return default = kwargs[name] try: if isinstance(default, bool) and not isinstance(value, bool): raise Exception( 'boolean value should be specifiec as --{0}/--no{0}' .format(name)) kwargs[name] = default.__class__(value) except Exception as e: logger.error('invalid argument for {!r}: {}'.format( name, e)) return # Run script. with treelog.HtmlLog(str(dst_log)), nutils.matrix.backend( 'scipy'), nutils.warnings.via(treelog.warning): script_dict['main'](**kwargs) (dst_log / 'log.html').rename(dst_log / 'index.html') refnode = docutils.nodes.reference('', '', internal=False, refuri=app.builder.get_relative_uri( env.docname, target)) refnode.append(contnode) return refnode