def test_generateLine_class( inv_writer_nolog: sphinx.SphinxInventoryWriter) -> None: """ Check inventory for class. """ result = inv_writer_nolog._generateLine( model.Class(IGNORE_SYSTEM, 'class1')) assert 'class1 py:class -1 class1.html -\n' == result
def test_generateLine_module( inv_writer_nolog: sphinx.SphinxInventoryWriter) -> None: """ Check inventory for module. """ result = inv_writer_nolog._generateLine( model.Module(IGNORE_SYSTEM, 'module1')) assert 'module1 py:module -1 module1.html -\n' == result
def test_generateLine_attribute( inv_writer_nolog: sphinx.SphinxInventoryWriter) -> None: """ Check inventory for attributes. """ parent = model.Class(IGNORE_SYSTEM, 'class1') result = inv_writer_nolog._generateLine( model.Attribute(IGNORE_SYSTEM, 'attr1', parent)) assert 'class1.attr1 py:attribute -1 class1.html#attr1 -\n' == result
def test_generateLine_method( inv_writer_nolog: sphinx.SphinxInventoryWriter) -> None: """ Check inventory for method. Methods are functions inside a class. """ parent = model.Class(IGNORE_SYSTEM, 'class1') result = inv_writer_nolog._generateLine( model.Function(IGNORE_SYSTEM, 'meth1', parent)) assert 'class1.meth1 py:method -1 class1.html#meth1 -\n' == result
def test_generateLine_function( inv_writer_nolog: sphinx.SphinxInventoryWriter) -> None: """ Check inventory for function. Functions are inside a module. """ parent = model.Module(IGNORE_SYSTEM, 'module1') result = inv_writer_nolog._generateLine( model.Function(IGNORE_SYSTEM, 'func1', parent)) assert 'module1.func1 py:function -1 module1.html#func1 -\n' == result
def test_generateContent( inv_writer_nolog: sphinx.SphinxInventoryWriter) -> None: """ Return a string with inventory for all targeted objects, recursive. """ system = model.System() root1 = model.Package(system, 'package1') root2 = model.Package(system, 'package2') child1 = model.Package(system, 'child1', parent=root2) system.addObject(child1) subjects = [root1, root2] result = inv_writer_nolog._generateContent(subjects) expected_result = ( b'package1 py:module -1 package1.html -\n' b'package2 py:module -1 package2.html -\n' b'package2.child1 py:module -1 package2.child1.html -\n') assert expected_result == result
def main(args=sys.argv[1:]): 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') if not issubclass(systemclass, model.System): msg = "%s is not a subclass of model.System" error(msg, systemclass) 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 if options.abbrevmapping: for thing in options.abbrevmapping.split(','): k, v = thing.split('=') system.abbrevmapping[k] = v # 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(e) except KeyError: pass if options.buildtime: try: system.buildtime = datetime.datetime.strptime( options.buildtime, BUILDTIME_FORMAT) except ValueError as e: error(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) for path in args: path = os.path.abspath(path) if path in system.packages: continue if os.path.isdir(path): system.msg('addPackage', 'adding directory ' + path) system.addPackage(path, prependedpackage) else: system.msg('addModuleFromPath', 'adding module ' + path) system.addModuleFromPath(prependedpackage, path) system.packages.append(path) # step 3: move the system to the desired state if not system.packages: error("The system does not contain any code, did you " "forget an --add-package?") system.process() if system.options.projectname is None: name = '/'.join(ro.name for ro in system.rootobjects) system.msg( 'warning', 'WARNING: guessing '+name+' for project name', thresh=-1) system.projectname = name else: system.projectname = system.options.projectname # step 4: make html, if desired if options.makehtml: options.makeintersphinx = True if options.htmlwriter: writerclass = findClassFromDottedName( options.htmlwriter, '--html-writer') else: from pydoctor import templatewriter writerclass = templatewriter.TemplateWriter system.msg('html', 'writing html to %s using %s.%s'%( options.htmloutput, writerclass.__module__, writerclass.__name__)) writer = writerclass(options.htmloutput) writer.system = system writer.prepOutputDirectory() if options.htmlsubjects: subjects = [] for fn in options.htmlsubjects: subjects.append(system.allobjects[fn]) elif options.htmlsummarypages: writer.writeModuleIndex(system) subjects = [] else: writer.writeModuleIndex(system) subjects = system.rootobjects writer.writeIndividualFiles(subjects, options.htmlfunctionpages) if system.docstring_syntax_errors: def p(msg): system.msg(('epytext', 'epytext-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 options.makeintersphinx: if not options.makehtml: subjects = system.rootobjects # Generate Sphinx inventory. sphinx_inventory = SphinxInventoryWriter( logger=system.msg, project_name=system.projectname, ) 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
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