def test_template_lookup_add_template_allok() -> None: here = Path(__file__).parent with warnings.catch_warnings(record=True) as catch_warnings: warnings.simplefilter("always") lookup = TemplateLookup() lookup.add_templatedir(here / 'testcustomtemplates' / 'allok') assert len(catch_warnings) == 0, [str(w.message) for w in catch_warnings]
def __init__(self, system: model.System, template_lookup: TemplateLookup): # Override L{Page.loader} because here the page L{filename} # does not equal the template filename. super().__init__( system=system, template_lookup=template_lookup, loader=template_lookup.get_template('summary.html').loader)
def __init__(self, filebase: str, template_lookup: Optional[TemplateLookup] = None): """ @arg filebase: Output directory. @arg template_lookup: Custom L{TemplateLookup} object. """ self.base: Path = Path(filebase) self.written_pages: int = 0 self.total_pages: int = 0 self.dry_run: bool = False self.template_lookup: TemplateLookup = ( template_lookup if template_lookup else TemplateLookup()) """Writer's L{TemplateLookup} object"""
def test_template_lookup_add_template_raises() -> None: lookup = TemplateLookup() with pytest.raises(UnsupportedTemplateVersion): lookup.add_template( _HtmlTemplate(name="nav.html", text=""" <nav class="navbar navbar-default" xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1"> <meta name="pydoctor-template-version" content="2050" /> <div class="container"> </div> </nav> """)) with pytest.raises(ValueError): lookup.add_template( _HtmlTemplate(name="nav.html", text=""" <nav class="navbar navbar-default" xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1"> <meta name="pydoctor-template-version" content="1" /> <div class="container"> </div> </nav> <span> Words </span> """))
def test_nonempty_table() -> None: mod = fromText('def f(): pass') t = ChildTable(pages.DocGetter(), mod, mod.contents.values(), ChildTable.lookup_loader(TemplateLookup())) flattened = flatten(t) assert 'The renderer named' not in flattened
def test_empty_table() -> None: mod = fromText('') t = ChildTable(pages.DocGetter(), mod, [], ChildTable.lookup_loader(TemplateLookup())) flattened = flatten(t) assert 'The renderer named' not in flattened
def test_template_lookup_add_template_warns() -> None: lookup = TemplateLookup() here = Path(__file__).parent with pytest.warns(UserWarning) as catch_warnings: with (here / 'testcustomtemplates' / 'faketemplate' / 'nav.html').open( 'r', encoding='utf-8') as fobj: lookup.add_template( _HtmlTemplate(text=fobj.read(), name='nav.html')) assert len(catch_warnings) == 1, [str(w.message) for w in catch_warnings] assert "Your custom template 'nav.html' is out of date" in str( catch_warnings.pop().message) with pytest.warns(UserWarning) as catch_warnings: with (here / 'testcustomtemplates' / 'faketemplate' / 'table.html').open('r', encoding='utf-8') as fobj: lookup.add_template( _HtmlTemplate(text=fobj.read(), name='table.html')) assert len(catch_warnings) == 1, [str(w.message) for w in catch_warnings] assert "Could not read 'table.html' template version" in str( catch_warnings.pop().message) with pytest.warns(UserWarning) as catch_warnings: with (here / 'testcustomtemplates' / 'faketemplate' / 'summary.html').open('r', encoding='utf-8') as fobj: lookup.add_template( _HtmlTemplate(text=fobj.read(), name='summary.html')) assert len(catch_warnings) == 1, [str(w.message) for w in catch_warnings] assert "Could not read 'summary.html' template version" in str( catch_warnings.pop().message) with pytest.warns(UserWarning) as catch_warnings: with (here / 'testcustomtemplates' / 'faketemplate' / 'random.html').open('r', encoding='utf-8') as fobj: lookup.add_template( _HtmlTemplate(text=fobj.read(), name='random.html')) assert len(catch_warnings) == 1, [str(w.message) for w in catch_warnings] assert "Invalid template filename 'random.html'" in str( catch_warnings.pop().message) with pytest.warns(UserWarning) as catch_warnings: lookup.add_templatedir(here / 'testcustomtemplates' / 'faketemplate') assert len(catch_warnings) == 4, [str(w.message) for w in catch_warnings]
def test_template_lookup_get_template() -> None: lookup = TemplateLookup() here = Path(__file__).parent assert lookup.get_template('index.html').text == filetext( here.parent / 'templates' / 'index.html') lookup.add_template( _HtmlTemplate(name='footer.html', text=filetext(here / 'testcustomtemplates' / 'faketemplate' / 'footer.html'))) assert lookup.get_template('footer.html').text == filetext( here / 'testcustomtemplates' / 'faketemplate' / 'footer.html') assert lookup.get_template('index.html').text == filetext( here.parent / 'templates' / 'index.html') lookup = TemplateLookup() assert lookup.get_template('footer.html').text == filetext( here.parent / 'templates' / 'footer.html') assert lookup.get_template('subheader.html').version == -1 assert lookup.get_template('table.html').version == 1
def test_html_template_version() -> None: lookup = TemplateLookup() for template in lookup._templates.values(): if isinstance(template, _HtmlTemplate) and not template.is_empty(): assert template.version >= 1
def main(args: Sequence[str] = sys.argv[1:]) -> int: """ This is the console_scripts entry point for pydoctor CLI. @param args: Command line arguments to run the CLI. """ options, args = parse_args(args) exitcode = 0 if options.configfile: readConfigFile(options) cache = prepareCache(clearCache=options.clear_intersphinx_cache, enableCache=options.enable_intersphinx_cache, cachePath=options.intersphinx_cache_path, maxAge=options.intersphinx_cache_max_age) try: # step 1: make/find the system if options.systemclass: systemclass = findClassFromDottedName(options.systemclass, '--system-class', model.System) else: systemclass = zopeinterface.ZopeInterfaceSystem system = systemclass(options) system.fetchIntersphinxInventories(cache) if options.htmlsourcebase: if options.projectbasedirectory is None: error("you must specify --project-base-dir " "when using --html-viewsource-base") system.sourcebase = options.htmlsourcebase # step 1.5: check that we're actually going to accomplish something here args = list(args) + options.modules + options.packages if options.makehtml == MAKE_HTML_DEFAULT: if not options.testing and not options.makeintersphinx: options.makehtml = True else: options.makehtml = False # Support source date epoch: # https://reproducible-builds.org/specs/source-date-epoch/ try: system.buildtime = datetime.datetime.utcfromtimestamp( int(os.environ['SOURCE_DATE_EPOCH'])) except ValueError as e: error(str(e)) except KeyError: pass if options.buildtime: try: system.buildtime = datetime.datetime.strptime( options.buildtime, BUILDTIME_FORMAT) except ValueError as e: error(str(e)) # step 2: add any packages and modules if args: prependedpackage = None if options.prependedpackage: for m in options.prependedpackage.split('.'): prependedpackage = system.Package(system, m, prependedpackage) system.addObject(prependedpackage) initmodule = system.Module(system, '__init__', prependedpackage) system.addObject(initmodule) added_paths = set() for arg in args: path = resolve_path(arg) if path in added_paths: continue if options.projectbasedirectory is not None: # Note: Path.is_relative_to() was only added in Python 3.9, # so we have to use this workaround for now. try: path.relative_to(options.projectbasedirectory) except ValueError as ex: error(f"Source path lies outside base directory: {ex}") if path.is_dir(): system.msg('addPackage', f"adding directory {path}") if not (path / '__init__.py').is_file(): error(f"Source directory lacks __init__.py: {path}") system.addPackage(path, prependedpackage) elif path.is_file(): system.msg('addModuleFromPath', f"adding module {path}") system.addModuleFromPath(path, prependedpackage) elif path.exists(): error(f"Source path is neither file nor directory: {path}") else: error(f"Source path does not exist: {path}") added_paths.add(path) else: error("No source paths given.") # step 3: move the system to the desired state if system.options.projectname is None: name = '/'.join(system.root_names) system.msg('warning', f"Guessing '{name}' for project name.", thresh=0) system.projectname = name else: system.projectname = system.options.projectname system.process() # step 4: make html, if desired if options.makehtml: options.makeintersphinx = True from pydoctor import templatewriter if options.htmlwriter: writerclass = findClassFromDottedName(options.htmlwriter, '--html-writer', IWriter) else: writerclass = templatewriter.TemplateWriter system.msg( 'html', 'writing html to %s using %s.%s' % (options.htmloutput, writerclass.__module__, writerclass.__name__)) writer: IWriter # Handle custom HTML templates if system.options.templatedir: custom_lookup = TemplateLookup() try: custom_lookup.add_templatedir( Path(system.options.templatedir)) except UnsupportedTemplateVersion as e: error(str(e)) try: # mypy error: Cannot instantiate abstract class 'IWriter' writer = writerclass( options.htmloutput, # type: ignore[abstract] template_lookup=custom_lookup) except TypeError: # Custom class does not accept 'template_lookup' argument. writer = writerclass( options.htmloutput) # type: ignore[abstract] warnings.warn( f"Writer '{writerclass.__name__}' does not support " "HTML template customization with --template-dir.") else: writer = writerclass( options.htmloutput) # type: ignore[abstract] writer.prepOutputDirectory() subjects: Sequence[model.Documentable] = () if options.htmlsubjects: subjects = [ system.allobjects[fn] for fn in options.htmlsubjects ] else: writer.writeSummaryPages(system) if not options.htmlsummarypages: subjects = system.rootobjects writer.writeIndividualFiles(subjects) if system.docstring_syntax_errors: def p(msg: str) -> None: system.msg('docstring-summary', msg, thresh=-1, topthresh=1) p("these %s objects' docstrings contain syntax errors:" % (len(system.docstring_syntax_errors), )) exitcode = 2 for fn in sorted(system.docstring_syntax_errors): p(' ' + fn) if system.violations and options.warnings_as_errors: # Update exit code if the run has produced warnings. exitcode = 3 if options.makeintersphinx: if not options.makehtml: subjects = system.rootobjects # Generate Sphinx inventory. sphinx_inventory = SphinxInventoryWriter( logger=system.msg, project_name=system.projectname, project_version=system.options.projectversion, ) if not os.path.exists(options.htmloutput): os.makedirs(options.htmloutput) sphinx_inventory.generate( subjects=subjects, basepath=options.htmloutput, ) except: if options.pdb: import pdb pdb.post_mortem(sys.exc_info()[2]) raise return exitcode