--- a/src/eric7/eric7_doc.py Wed Nov 08 17:07:15 2023 +0100 +++ b/src/eric7/eric7_doc.py Wed Nov 08 17:07:37 2023 +0100 @@ -12,8 +12,8 @@ This script can be used via the commandline as well. """ +import argparse import fnmatch -import getopt import glob import os import shutil @@ -32,93 +32,199 @@ supportedExtensions = [".py", ".pyw", ".ptl", ".rb"] -def usage(): +def createArgumentParser(): """ - Function to print some usage information. + Function to create an argument parser. - It prints a reference of all commandline parameters that may - be used and ends the application. + @return created argument parser object + @rtype argparse.ArgumentParser """ - print("eric7_doc") - print() - print("Copyright (c) 2003 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>.") - print() - print("Usage:") - print() - print(" eric7_doc [options] files...") - print() - print("where files can be either python modules, package") - print("directories or ordinary directories.") - print() - print("Options:") - print() - print(" -c filename or --style-sheet=filename") - print(" Specify a CSS style sheet file to be used.") - print(" -e or --noempty") - print(" Don't include empty modules.") - print(" --eol=eol-type") - print(" Use the given eol type to terminate lines.") - print(" Valid values are 'cr', 'lf' and 'crlf'.") - print(" --exclude-file=pattern") - print(" Specify a filename pattern of files to be excluded.") - print(" This option may be repeated multiple times.") - print(" -h or --help") - print(" Show this help and exit.") - print(" -i or --noindex") - print(" Don't generate index files.") - print(" -o directory or --outdir=directory") - print(" Generate files in the named directory.") - print(" -R, -r or --recursive") - print(" Perform a recursive search for Python files.") - print(" -s directory or --startdir=directory") - print(" Start the documentation generation in the given directory.") - print(" -t ext or --extension=ext") - print(" Add the given extension to the list of file extensions.") - print(" This option may be given multiple times.") - print(" -V or --version") - print(" Show version information and exit.") - print(" -x directory or --exclude=directory") - print(" Specify a directory basename to be excluded.") - print(" This option may be repeated multiple times.") - print() - print(" --body-color=color") - print(" Specify the text color.") - print(" --body-background-color=color") - print(" Specify the text background color.") - print(" --l1header-color=color") - print(" Specify the text color of level 1 headers.") - print(" --l1header-background-color=color") - print(" Specify the text background color of level 1 headers.") - print(" --l2header-color=color") - print(" Specify the text color of level 2 headers.") - print(" --l2header-background-color=color") - print(" Specify the text background color of level 2 headers.") - print(" --cfheader-color=color") - print(" Specify the text color of class and function headers.") - print(" --cfheader-background-color=color") - print(" Specify the text background color of class and function headers.") - print(" --link-color=color") - print(" Specify the text color of hyperlinks.") - print() - print(" --create-qhp") - print(" Enable generation of QtHelp files.") - print(" --qhp-outdir=directory") - print(" Generate QtHelp files in the named directory.") - print(" --qhp-namespace=namespace") - print(" Use the given namespace (mandatory).") - print(" --qhp-virtualfolder=folder") - print(" Use the given virtual folder (mandatory).") - print(" The virtual folder must not contain '/'.") - print(" --qhp-filtername=name") - print(" Use the given name for the custom filter.") - print(" --qhp-filterattribs=attributes") - print(" Add the given attributes to the filter list.") - print(" Attributes must be separated by ':'.") - print(" --qhp-title=title") - print(" Use this as the title for the generated help (mandatory).") - print(" --create-qhc") - print(" Enable generation of QtHelp Collection files.") - sys.exit(1) + parser = argparse.ArgumentParser( + description="Create source code documentation files.", + epilog="Copyright (c) 2004 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>.", + add_help=False, + ) + + parser.add_argument( + "file", + nargs="*", + help="'file' can be either python modules, package directories or ordinary" + " directories. At least one 'file' argument must be given.", + ) + parser.add_argument( + "-c", + "--style-sheet", + default="", + help="Specify a CSS style sheet file to be used.", + ) + parser.add_argument( + "-e", + "--no-empty", + action="store_true", + help="Don't include empty modules.", + ) + parser.add_argument( + "--eol", + choices=["cr", "lf", "crlf"], + help="Use the given eol type to terminate lines.", + ) + parser.add_argument( + "--exclude-file", + action="append", + default=[], + help="Specify a filename pattern of files to be excluded. This option may be" + " repeated multiple times.", + ) + parser.add_argument( + "-h", + "--help", + action="store_true", + help="Show this help and exit.", + ) + parser.add_argument( + "-i", + "--no-index", + action="store_true", + help="Don't generate index files.", + ) + parser.add_argument( + "-o", + "--outdir", + default="doc", + help="Generate files in the named directory.", + ) + parser.add_argument( + "-R", + "-r", + "--recursive", + action="store_true", + help="Perform a recursive search for source files.", + ) + parser.add_argument( + "-s", + "--startdir", + default="", + help="Start the documentation generation in the given directory.", + ) + parser.add_argument( + "-t", + "--extension", + action="append", + default=[], + help="Add the given extension to the list of file extensions. This option may" + " be given multiple times.", + ) + parser.add_argument( + "-V", + "--version", + action="store_true", + help="Show version information and exit.", + ) + parser.add_argument( + "-x", + "--exclude", + action="append", + default=[], + help="Specify a directory basename to be excluded. This option may be repeated" + " multiple times.", + ) + + colorGroup = parser.add_argument_group( + "Stylesheet Colors", "Parameters to define individual stylesheet colors." + ) + colorGroup.add_argument( + "--body-color", + default=eric7docDefaultColors["BodyColor"], + help="Specify the text color.", + ) + colorGroup.add_argument( + "--body-background-color", + default=eric7docDefaultColors["BodyBgColor"], + help="Specify the text background color.", + ) + colorGroup.add_argument( + "--l1header-color", + default=eric7docDefaultColors["Level1HeaderColor"], + help="Specify the text color of level 1 headers.", + ) + colorGroup.add_argument( + "--l1header-background-color", + default=eric7docDefaultColors["Level1HeaderBgColor"], + help="Specify the text background color of level 1 headers.", + ) + colorGroup.add_argument( + "--l2header-color", + default=eric7docDefaultColors["Level2HeaderColor"], + help="Specify the text color of level 2 headers.", + ) + colorGroup.add_argument( + "--l2header-background-color", + default=eric7docDefaultColors["Level2HeaderBgColor"], + help="Specify the text background color of level 2 headers.", + ) + colorGroup.add_argument( + "--cfheader-color", + default=eric7docDefaultColors["CFColor"], + help="Specify the text color of class and function headers.", + ) + colorGroup.add_argument( + "--cfheader-background-color", + default=eric7docDefaultColors["CFBgColor"], + help="Specify the text background color of class and function headers.", + ) + colorGroup.add_argument( + "--link-color", + default=eric7docDefaultColors["LinkColor"], + help="Specify the text color of hyperlinks.", + ) + + qtGroup = parser.add_argument_group( + "QtHelp", "Parameters for QtHelp file creation." + ) + qtGroup.add_argument( + "--create-qhp", + action="store_true", + help="Enable generation of QtHelp files.", + ) + qtGroup.add_argument( + "--qhp-outdir", + default="help", + help="Store the QtHelp files in the named directory.", + ) + qtGroup.add_argument( + "--qhp-namespace", + default="", + help="Use the given namespace (required).", + ) + qtGroup.add_argument( + "--qhp-virtualfolder", + default="source", + help="Use the given virtual folder (mandatory). The virtual folder must not" + " contain '/'.", + ) + qtGroup.add_argument( + "--qhp-filtername", + default="unknown", + help="Use the given name for the custom filter.", + ) + qtGroup.add_argument( + "--qhp-filterattribs", + default="", + help="Add the given attributes to the filter list. Attributes must be" + " separated by ':'.", + ) + qtGroup.add_argument( + "--qhp-title", + default="", + help="Use this as the title for the generated help (mandatory).", + ) + qtGroup.add_argument( + "--create-qhc", + action="store_true", + help="Enable generation of QtHelp Collection files.", + ) + + return parser def version(): @@ -145,44 +251,21 @@ """ Main entry point into the application. """ - try: - opts, args = getopt.getopt( - sys.argv[1:], - "c:ehio:Rrs:t:Vx:", - [ - "exclude=", - "extension=", - "help", - "noindex", - "noempty", - "outdir=", - "recursive", - "startdir=", - "style-sheet=", - "version", - "exclude-file=", - "eol=", - "body-color=", - "body-background-color=", - "l1header-color=", - "l1header-background-color=", - "l2header-color=", - "l2header-background-color=", - "cfheader-color=", - "cfheader-background-color=", - "link-color=", - "create-qhp", - "qhp-outdir=", - "qhp-namespace=", - "qhp-virtualfolder=", - "qhp-filtername=", - "qhp-filterattribs=", - "qhp-title=", - "create-qhc", - ], + parser = createArgumentParser() + args = parser.parse_args() + + if args.help: + parser.print_help() + sys.exit(1) + elif args.version: + version() + sys.exit(1) + + if not args.file: + parser.error( + "At least one file, Python module, Python package or directory must be" + " given." ) - except getopt.error: - usage() excludeDirs = [ ".svn", @@ -196,98 +279,41 @@ "doc", "docs", "__pycache__", - ] - excludePatterns = [] - startDir = "" - outputDir = "doc" - recursive = False - doIndex = True - noempty = False - newline = None - - stylesheetFile = "" - colors = eric7docDefaultColors.copy() - - qtHelpCreation = False - qtHelpOutputDir = "help" - qtHelpNamespace = "" - qtHelpFolder = "source" - qtHelpFilterName = "unknown" - qtHelpFilterAttribs = "" - qtHelpTitle = "" - qtHelpCreateCollection = False + ] + args.exclude + excludePatterns = args.exclude_file + startDir = args.startdir + outputDir = args.outdir + recursive = args.recursive + doIndex = not args.no_index + noempty = args.no_empty + newline = { + "cr": "\r", + "lf": "\n", + "crlf": "\r\n", + }.get(args.eol) - for k, v in opts: - if k in ["-s", "--startdir"]: - startDir = v - elif k in ["-o", "--outdir"]: - outputDir = v - elif k in ["-R", "-r", "--recursive"]: - recursive = True - elif k in ["-x", "--exclude"]: - excludeDirs.append(v) - elif k == "--exclude-file": - excludePatterns.append(v) - elif k in ["-i", "--noindex"]: - doIndex = False - elif k in ["-e", "--noempty"]: - noempty = True - elif k in ["-h", "--help"]: - usage() - elif k in ["-V", "--version"]: - version() - elif k in ["-c", "--style-sheet"]: - stylesheetFile = v - elif k in ["-t", "--extension"]: - if v.strip() and not v.startswith("."): - v = ".{0}".format(v) - supportedExtensions.append(v) - elif k == "--eol": - if v.lower() == "cr": - newline = "\r" - elif v.lower() == "lf": - newline = "\n" - elif v.lower() == "crlf": - newline = "\r\n" + stylesheetFile = args.style_sheet + colors = eric7docDefaultColors.copy() + colors = { + "BodyColor": args.body_color, + "BodyBgColor": args.body_background_color, + "Level1HeaderColor": args.l1header_color, + "Level1HeaderBgColor": args.l1header_background_color, + "Level2HeaderColor": args.l2header_color, + "Level2HeaderBgColor": args.l2header_background_color, + "CFColor": args.cfheader_color, + "CFBgColor": args.cfheader_background_color, + "LinkColor": args.link_color, + } - elif k == "--body-color": - colors["BodyColor"] = v - elif k == "--body-background-color": - colors["BodyBgColor"] = v - elif k == "--l1header-color": - colors["Level1HeaderColor"] = v - elif k == "--l1header-background-color": - colors["Level1HeaderBgColor"] = v - elif k == "--l2header-color": - colors["Level2HeaderColor"] = v - elif k == "--l2header-background-color": - colors["Level2HeaderBgColor"] = v - elif k == "--cfheader-color": - colors["CFColor"] = v - elif k == "--cfheader-background-color": - colors["CFBgColor"] = v - elif k == "--link-color": - colors["LinkColor"] = v - - elif k == "--create-qhp": - qtHelpCreation = True - elif k == "--qhp-outdir": - qtHelpOutputDir = v - elif k == "--qhp-namespace": - qtHelpNamespace = v - elif k == "--qhp-virtualfolder": - qtHelpFolder = v - elif k == "--qhp-filtername": - qtHelpFilterName = v - elif k == "--qhp-filterattribs": - qtHelpFilterAttribs = v - elif k == "--qhp-title": - qtHelpTitle = v - elif k == "--create-qhc": - qtHelpCreateCollection = True - - if not args: - usage() + qtHelpCreation = args.create_qhp + qtHelpOutputDir = args.qhp_outdir + qtHelpNamespace = args.qhp_namespace + qtHelpFolder = args.qhp_virtualfolder + qtHelpFilterName = args.qhp_filtername + qtHelpFilterAttribs = args.qhp_filterattribs + qtHelpTitle = args.qhp_title + qtHelpCreateCollection = args.create_qhc if qtHelpCreation and ( qtHelpNamespace == "" @@ -295,7 +321,7 @@ or "/" in qtHelpFolder or qtHelpTitle == "" ): - usage() + parser.error("Some required QtHelp arguments are missing.") basename = "" @@ -307,7 +333,7 @@ sys.stderr.write( "Could not create output directory {0}.".format(outputDir) ) - sys.exit(2) + sys.exit(3) else: outputDir = os.getcwd() outputDir = os.path.abspath(outputDir) @@ -319,7 +345,7 @@ sys.stderr.write( "The CSS stylesheet '{0}' does not exist\n".format(stylesheetFile) ) - sys.exit(2) + sys.exit(3) else: try: with open(os.path.join(outputDir, "styles.css"), "w") as sf: @@ -328,7 +354,7 @@ sys.stderr.write( "The CSS stylesheet '{0}' could not be created\n".format(stylesheetFile) ) - sys.exit(2) + sys.exit(3) indexGenerator = IndexGenerator(outputDir) @@ -343,7 +369,7 @@ qtHelpOutputDir ) ) - sys.exit(2) + sys.exit(3) else: qtHelpOutputDir = os.getcwd() qtHelpOutputDir = os.path.abspath(qtHelpOutputDir) @@ -362,29 +388,29 @@ if startDir: os.chdir(os.path.abspath(startDir)) - for arg in args: - if os.path.isdir(arg): + for argsfile in args.file: + if os.path.isdir(argsfile): if os.path.exists( - os.path.join(arg, FileSystemUtilities.joinext("__init__", ".py")) + os.path.join(argsfile, FileSystemUtilities.joinext("__init__", ".py")) ): - basename = os.path.dirname(arg) - if arg == ".": + basename = os.path.dirname(argsfile) + if argsfile == ".": sys.stderr.write("The directory '.' is a package.\n") sys.stderr.write("Please repeat the call giving its real name.\n") sys.stderr.write("Ignoring the directory.\n") continue else: - basename = arg + basename = argsfile if basename: basename = "{0}{1}".format(basename, os.sep) - if recursive and not os.path.islink(arg): - names = [arg] + FileSystemUtilities.getDirs(arg, excludeDirs) + if recursive and not os.path.islink(argsfile): + names = [argsfile] + FileSystemUtilities.getDirs(argsfile, excludeDirs) else: - names = [arg] + names = [argsfile] else: basename = "" - names = [arg] + names = [argsfile] for filename in names: inpackage = False