src/eric7/eric7_doc.py

branch
eric7
changeset 10296
2d3218cb56dc
parent 9786
f94b530722af
child 10298
a148416e7e7d
equal deleted inserted replaced
10295:e0e7f81cc164 10296:2d3218cb56dc
10 This is the main Python script of the documentation generator. It is 10 This is the main Python script of the documentation generator. It is
11 this script that gets called via the source documentation interface. 11 this script that gets called via the source documentation interface.
12 This script can be used via the commandline as well. 12 This script can be used via the commandline as well.
13 """ 13 """
14 14
15 import argparse
15 import fnmatch 16 import fnmatch
16 import getopt
17 import glob 17 import glob
18 import os 18 import os
19 import shutil 19 import shutil
20 import sys 20 import sys
21 21
30 30
31 # list of supported filename extensions 31 # list of supported filename extensions
32 supportedExtensions = [".py", ".pyw", ".ptl", ".rb"] 32 supportedExtensions = [".py", ".pyw", ".ptl", ".rb"]
33 33
34 34
35 def usage(): 35 def createArgumentParser():
36 """ 36 """
37 Function to print some usage information. 37 Function to create an argument parser.
38 38
39 It prints a reference of all commandline parameters that may 39 @return created argument parser object
40 be used and ends the application. 40 @rtype argparse.ArgumentParser
41 """ 41 """
42 print("eric7_doc") 42 parser = argparse.ArgumentParser(
43 print() 43 description="Create source code documentation files.",
44 print("Copyright (c) 2003 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>.") 44 epilog="Copyright (c) 2004 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>.",
45 print() 45 add_help=False,
46 print("Usage:") 46 )
47 print() 47
48 print(" eric7_doc [options] files...") 48 parser.add_argument(
49 print() 49 "file",
50 print("where files can be either python modules, package") 50 nargs="*",
51 print("directories or ordinary directories.") 51 help="'file' can be either python modules, package directories or ordinary"
52 print() 52 " directories. At least one 'file' argument must be given.",
53 print("Options:") 53 )
54 print() 54 parser.add_argument(
55 print(" -c filename or --style-sheet=filename") 55 "-c",
56 print(" Specify a CSS style sheet file to be used.") 56 "--style-sheet",
57 print(" -e or --noempty") 57 default="",
58 print(" Don't include empty modules.") 58 help="Specify a CSS style sheet file to be used.",
59 print(" --eol=eol-type") 59 )
60 print(" Use the given eol type to terminate lines.") 60 parser.add_argument(
61 print(" Valid values are 'cr', 'lf' and 'crlf'.") 61 "-e",
62 print(" --exclude-file=pattern") 62 "--no-empty",
63 print(" Specify a filename pattern of files to be excluded.") 63 action="store_true",
64 print(" This option may be repeated multiple times.") 64 help="Don't include empty modules.",
65 print(" -h or --help") 65 )
66 print(" Show this help and exit.") 66 parser.add_argument(
67 print(" -i or --noindex") 67 "--eol",
68 print(" Don't generate index files.") 68 choices=["cr", "lf", "crlf"],
69 print(" -o directory or --outdir=directory") 69 help="Use the given eol type to terminate lines.",
70 print(" Generate files in the named directory.") 70 )
71 print(" -R, -r or --recursive") 71 parser.add_argument(
72 print(" Perform a recursive search for Python files.") 72 "--exclude-file",
73 print(" -s directory or --startdir=directory") 73 action="append",
74 print(" Start the documentation generation in the given directory.") 74 default=[],
75 print(" -t ext or --extension=ext") 75 help="Specify a filename pattern of files to be excluded. This option may be"
76 print(" Add the given extension to the list of file extensions.") 76 " repeated multiple times.",
77 print(" This option may be given multiple times.") 77 )
78 print(" -V or --version") 78 parser.add_argument(
79 print(" Show version information and exit.") 79 "-h",
80 print(" -x directory or --exclude=directory") 80 "--help",
81 print(" Specify a directory basename to be excluded.") 81 action="store_true",
82 print(" This option may be repeated multiple times.") 82 help="Show this help and exit.",
83 print() 83 )
84 print(" --body-color=color") 84 parser.add_argument(
85 print(" Specify the text color.") 85 "-i",
86 print(" --body-background-color=color") 86 "--no-index",
87 print(" Specify the text background color.") 87 action="store_true",
88 print(" --l1header-color=color") 88 help="Don't generate index files.",
89 print(" Specify the text color of level 1 headers.") 89 )
90 print(" --l1header-background-color=color") 90 parser.add_argument(
91 print(" Specify the text background color of level 1 headers.") 91 "-o",
92 print(" --l2header-color=color") 92 "--outdir",
93 print(" Specify the text color of level 2 headers.") 93 default="doc",
94 print(" --l2header-background-color=color") 94 help="Generate files in the named directory.",
95 print(" Specify the text background color of level 2 headers.") 95 )
96 print(" --cfheader-color=color") 96 parser.add_argument(
97 print(" Specify the text color of class and function headers.") 97 "-R",
98 print(" --cfheader-background-color=color") 98 "-r",
99 print(" Specify the text background color of class and function headers.") 99 "--recursive",
100 print(" --link-color=color") 100 action="store_true",
101 print(" Specify the text color of hyperlinks.") 101 help="Perform a recursive search for source files.",
102 print() 102 )
103 print(" --create-qhp") 103 parser.add_argument(
104 print(" Enable generation of QtHelp files.") 104 "-s",
105 print(" --qhp-outdir=directory") 105 "--startdir",
106 print(" Generate QtHelp files in the named directory.") 106 default="",
107 print(" --qhp-namespace=namespace") 107 help="Start the documentation generation in the given directory.",
108 print(" Use the given namespace (mandatory).") 108 )
109 print(" --qhp-virtualfolder=folder") 109 parser.add_argument(
110 print(" Use the given virtual folder (mandatory).") 110 "-t",
111 print(" The virtual folder must not contain '/'.") 111 "--extension",
112 print(" --qhp-filtername=name") 112 action="append",
113 print(" Use the given name for the custom filter.") 113 default=[],
114 print(" --qhp-filterattribs=attributes") 114 help="Add the given extension to the list of file extensions. This option may"
115 print(" Add the given attributes to the filter list.") 115 " be given multiple times.",
116 print(" Attributes must be separated by ':'.") 116 )
117 print(" --qhp-title=title") 117 parser.add_argument(
118 print(" Use this as the title for the generated help (mandatory).") 118 "-V",
119 print(" --create-qhc") 119 "--version",
120 print(" Enable generation of QtHelp Collection files.") 120 action="store_true",
121 sys.exit(1) 121 help="Show version information and exit.",
122 )
123 parser.add_argument(
124 "-x",
125 "--exclude",
126 action="append",
127 default=[],
128 help="Specify a directory basename to be excluded. This option may be repeated"
129 " multiple times.",
130 )
131
132 colorGroup = parser.add_argument_group(
133 "Stylesheet Colors", "Parameters to define individual stylesheet colors."
134 )
135 colorGroup.add_argument(
136 "--body-color",
137 default=eric7docDefaultColors["BodyColor"],
138 help="Specify the text color.",
139 )
140 colorGroup.add_argument(
141 "--body-background-color",
142 default=eric7docDefaultColors["BodyBgColor"],
143 help="Specify the text background color.",
144 )
145 colorGroup.add_argument(
146 "--l1header-color",
147 default=eric7docDefaultColors["Level1HeaderColor"],
148 help="Specify the text color of level 1 headers.",
149 )
150 colorGroup.add_argument(
151 "--l1header-background-color",
152 default=eric7docDefaultColors["Level1HeaderBgColor"],
153 help="Specify the text background color of level 1 headers.",
154 )
155 colorGroup.add_argument(
156 "--l2header-color",
157 default=eric7docDefaultColors["Level2HeaderColor"],
158 help="Specify the text color of level 2 headers.",
159 )
160 colorGroup.add_argument(
161 "--l2header-background-color",
162 default=eric7docDefaultColors["Level2HeaderBgColor"],
163 help="Specify the text background color of level 2 headers.",
164 )
165 colorGroup.add_argument(
166 "--cfheader-color",
167 default=eric7docDefaultColors["CFColor"],
168 help="Specify the text color of class and function headers.",
169 )
170 colorGroup.add_argument(
171 "--cfheader-background-color",
172 default=eric7docDefaultColors["CFBgColor"],
173 help="Specify the text background color of class and function headers.",
174 )
175 colorGroup.add_argument(
176 "--link-color",
177 default=eric7docDefaultColors["LinkColor"],
178 help="Specify the text color of hyperlinks.",
179 )
180
181 qtGroup = parser.add_argument_group(
182 "QtHelp", "Parameters for QtHelp file creation."
183 )
184 qtGroup.add_argument(
185 "--create-qhp",
186 action="store_true",
187 help="Enable generation of QtHelp files.",
188 )
189 qtGroup.add_argument(
190 "--qhp-outdir",
191 default="help",
192 help="Store the QtHelp files in the named directory.",
193 )
194 qtGroup.add_argument(
195 "--qhp-namespace",
196 default="",
197 help="Use the given namespace (required).",
198 )
199 qtGroup.add_argument(
200 "--qhp-virtualfolder",
201 default="source",
202 help="Use the given virtual folder (mandatory). The virtual folder must not"
203 " contain '/'.",
204 )
205 qtGroup.add_argument(
206 "--qhp-filtername",
207 default="unknown",
208 help="Use the given name for the custom filter.",
209 )
210 qtGroup.add_argument(
211 "--qhp-filterattribs",
212 default="",
213 help="Add the given attributes to the filter list. Attributes must be"
214 " separated by ':'.",
215 )
216 qtGroup.add_argument(
217 "--qhp-title",
218 default="",
219 help="Use this as the title for the generated help (mandatory).",
220 )
221 qtGroup.add_argument(
222 "--create-qhc",
223 action="store_true",
224 help="Enable generation of QtHelp Collection files.",
225 )
226
227 return parser
122 228
123 229
124 def version(): 230 def version():
125 """ 231 """
126 Function to show the version information. 232 Function to show the version information.
143 249
144 def main(): 250 def main():
145 """ 251 """
146 Main entry point into the application. 252 Main entry point into the application.
147 """ 253 """
148 try: 254 parser = createArgumentParser()
149 opts, args = getopt.getopt( 255 args = parser.parse_args()
150 sys.argv[1:], 256
151 "c:ehio:Rrs:t:Vx:", 257 if args.help:
152 [ 258 parser.print_help()
153 "exclude=", 259 sys.exit(1)
154 "extension=", 260 elif args.version:
155 "help", 261 version()
156 "noindex", 262 sys.exit(1)
157 "noempty", 263
158 "outdir=", 264 if not args.file:
159 "recursive", 265 parser.error(
160 "startdir=", 266 "At least one file, Python module, Python package or directory must be"
161 "style-sheet=", 267 " given."
162 "version",
163 "exclude-file=",
164 "eol=",
165 "body-color=",
166 "body-background-color=",
167 "l1header-color=",
168 "l1header-background-color=",
169 "l2header-color=",
170 "l2header-background-color=",
171 "cfheader-color=",
172 "cfheader-background-color=",
173 "link-color=",
174 "create-qhp",
175 "qhp-outdir=",
176 "qhp-namespace=",
177 "qhp-virtualfolder=",
178 "qhp-filtername=",
179 "qhp-filterattribs=",
180 "qhp-title=",
181 "create-qhc",
182 ],
183 ) 268 )
184 except getopt.error:
185 usage()
186 269
187 excludeDirs = [ 270 excludeDirs = [
188 ".svn", 271 ".svn",
189 ".hg", 272 ".hg",
190 ".git", 273 ".git",
194 "dist", 277 "dist",
195 "build", 278 "build",
196 "doc", 279 "doc",
197 "docs", 280 "docs",
198 "__pycache__", 281 "__pycache__",
199 ] 282 ] + args.exclude
200 excludePatterns = [] 283 excludePatterns = args.exclude_file
201 startDir = "" 284 startDir = args.startdir
202 outputDir = "doc" 285 outputDir = args.outdir
203 recursive = False 286 recursive = args.recursive
204 doIndex = True 287 doIndex = not args.no_index
205 noempty = False 288 noempty = args.no_empty
206 newline = None 289 newline = {
207 290 "cr": "\r",
208 stylesheetFile = "" 291 "lf": "\n",
292 "crlf": "\r\n",
293 }.get(args.eol)
294
295 stylesheetFile = args.style_sheet
209 colors = eric7docDefaultColors.copy() 296 colors = eric7docDefaultColors.copy()
210 297 colors = {
211 qtHelpCreation = False 298 "BodyColor": args.body_color,
212 qtHelpOutputDir = "help" 299 "BodyBgColor": args.body_background_color,
213 qtHelpNamespace = "" 300 "Level1HeaderColor": args.l1header_color,
214 qtHelpFolder = "source" 301 "Level1HeaderBgColor": args.l1header_background_color,
215 qtHelpFilterName = "unknown" 302 "Level2HeaderColor": args.l2header_color,
216 qtHelpFilterAttribs = "" 303 "Level2HeaderBgColor": args.l2header_background_color,
217 qtHelpTitle = "" 304 "CFColor": args.cfheader_color,
218 qtHelpCreateCollection = False 305 "CFBgColor": args.cfheader_background_color,
219 306 "LinkColor": args.link_color,
220 for k, v in opts: 307 }
221 if k in ["-s", "--startdir"]: 308
222 startDir = v 309 qtHelpCreation = args.create_qhp
223 elif k in ["-o", "--outdir"]: 310 qtHelpOutputDir = args.qhp_outdir
224 outputDir = v 311 qtHelpNamespace = args.qhp_namespace
225 elif k in ["-R", "-r", "--recursive"]: 312 qtHelpFolder = args.qhp_virtualfolder
226 recursive = True 313 qtHelpFilterName = args.qhp_filtername
227 elif k in ["-x", "--exclude"]: 314 qtHelpFilterAttribs = args.qhp_filterattribs
228 excludeDirs.append(v) 315 qtHelpTitle = args.qhp_title
229 elif k == "--exclude-file": 316 qtHelpCreateCollection = args.create_qhc
230 excludePatterns.append(v)
231 elif k in ["-i", "--noindex"]:
232 doIndex = False
233 elif k in ["-e", "--noempty"]:
234 noempty = True
235 elif k in ["-h", "--help"]:
236 usage()
237 elif k in ["-V", "--version"]:
238 version()
239 elif k in ["-c", "--style-sheet"]:
240 stylesheetFile = v
241 elif k in ["-t", "--extension"]:
242 if v.strip() and not v.startswith("."):
243 v = ".{0}".format(v)
244 supportedExtensions.append(v)
245 elif k == "--eol":
246 if v.lower() == "cr":
247 newline = "\r"
248 elif v.lower() == "lf":
249 newline = "\n"
250 elif v.lower() == "crlf":
251 newline = "\r\n"
252
253 elif k == "--body-color":
254 colors["BodyColor"] = v
255 elif k == "--body-background-color":
256 colors["BodyBgColor"] = v
257 elif k == "--l1header-color":
258 colors["Level1HeaderColor"] = v
259 elif k == "--l1header-background-color":
260 colors["Level1HeaderBgColor"] = v
261 elif k == "--l2header-color":
262 colors["Level2HeaderColor"] = v
263 elif k == "--l2header-background-color":
264 colors["Level2HeaderBgColor"] = v
265 elif k == "--cfheader-color":
266 colors["CFColor"] = v
267 elif k == "--cfheader-background-color":
268 colors["CFBgColor"] = v
269 elif k == "--link-color":
270 colors["LinkColor"] = v
271
272 elif k == "--create-qhp":
273 qtHelpCreation = True
274 elif k == "--qhp-outdir":
275 qtHelpOutputDir = v
276 elif k == "--qhp-namespace":
277 qtHelpNamespace = v
278 elif k == "--qhp-virtualfolder":
279 qtHelpFolder = v
280 elif k == "--qhp-filtername":
281 qtHelpFilterName = v
282 elif k == "--qhp-filterattribs":
283 qtHelpFilterAttribs = v
284 elif k == "--qhp-title":
285 qtHelpTitle = v
286 elif k == "--create-qhc":
287 qtHelpCreateCollection = True
288
289 if not args:
290 usage()
291 317
292 if qtHelpCreation and ( 318 if qtHelpCreation and (
293 qtHelpNamespace == "" 319 qtHelpNamespace == ""
294 or qtHelpFolder == "" 320 or qtHelpFolder == ""
295 or "/" in qtHelpFolder 321 or "/" in qtHelpFolder
296 or qtHelpTitle == "" 322 or qtHelpTitle == ""
297 ): 323 ):
298 usage() 324 parser.error("Some required QtHelp arguments are missing.")
299 325
300 basename = "" 326 basename = ""
301 327
302 if outputDir: 328 if outputDir:
303 if not os.path.isdir(outputDir): 329 if not os.path.isdir(outputDir):
305 os.makedirs(outputDir) 331 os.makedirs(outputDir)
306 except OSError: 332 except OSError:
307 sys.stderr.write( 333 sys.stderr.write(
308 "Could not create output directory {0}.".format(outputDir) 334 "Could not create output directory {0}.".format(outputDir)
309 ) 335 )
310 sys.exit(2) 336 sys.exit(3)
311 else: 337 else:
312 outputDir = os.getcwd() 338 outputDir = os.getcwd()
313 outputDir = os.path.abspath(outputDir) 339 outputDir = os.path.abspath(outputDir)
314 340
315 if stylesheetFile: 341 if stylesheetFile:
317 shutil.copy(stylesheetFile, os.path.join(outputDir, "styles.css")) 343 shutil.copy(stylesheetFile, os.path.join(outputDir, "styles.css"))
318 except OSError: 344 except OSError:
319 sys.stderr.write( 345 sys.stderr.write(
320 "The CSS stylesheet '{0}' does not exist\n".format(stylesheetFile) 346 "The CSS stylesheet '{0}' does not exist\n".format(stylesheetFile)
321 ) 347 )
322 sys.exit(2) 348 sys.exit(3)
323 else: 349 else:
324 try: 350 try:
325 with open(os.path.join(outputDir, "styles.css"), "w") as sf: 351 with open(os.path.join(outputDir, "styles.css"), "w") as sf:
326 sf.write(TemplatesListsStyleCSS.cssTemplate.format(**colors)) 352 sf.write(TemplatesListsStyleCSS.cssTemplate.format(**colors))
327 except OSError: 353 except OSError:
328 sys.stderr.write( 354 sys.stderr.write(
329 "The CSS stylesheet '{0}' could not be created\n".format(stylesheetFile) 355 "The CSS stylesheet '{0}' could not be created\n".format(stylesheetFile)
330 ) 356 )
331 sys.exit(2) 357 sys.exit(3)
332 358
333 indexGenerator = IndexGenerator(outputDir) 359 indexGenerator = IndexGenerator(outputDir)
334 360
335 if qtHelpCreation: 361 if qtHelpCreation:
336 if qtHelpOutputDir: 362 if qtHelpOutputDir:
341 sys.stderr.write( 367 sys.stderr.write(
342 "Could not create QtHelp output directory {0}.".format( 368 "Could not create QtHelp output directory {0}.".format(
343 qtHelpOutputDir 369 qtHelpOutputDir
344 ) 370 )
345 ) 371 )
346 sys.exit(2) 372 sys.exit(3)
347 else: 373 else:
348 qtHelpOutputDir = os.getcwd() 374 qtHelpOutputDir = os.getcwd()
349 qtHelpOutputDir = os.path.abspath(qtHelpOutputDir) 375 qtHelpOutputDir = os.path.abspath(qtHelpOutputDir)
350 376
351 qtHelpGenerator = QtHelpGenerator( 377 qtHelpGenerator = QtHelpGenerator(
360 ) 386 )
361 387
362 if startDir: 388 if startDir:
363 os.chdir(os.path.abspath(startDir)) 389 os.chdir(os.path.abspath(startDir))
364 390
365 for arg in args: 391 for argsfile in args.file:
366 if os.path.isdir(arg): 392 if os.path.isdir(argsfile):
367 if os.path.exists( 393 if os.path.exists(
368 os.path.join(arg, FileSystemUtilities.joinext("__init__", ".py")) 394 os.path.join(argsfile, FileSystemUtilities.joinext("__init__", ".py"))
369 ): 395 ):
370 basename = os.path.dirname(arg) 396 basename = os.path.dirname(argsfile)
371 if arg == ".": 397 if argsfile == ".":
372 sys.stderr.write("The directory '.' is a package.\n") 398 sys.stderr.write("The directory '.' is a package.\n")
373 sys.stderr.write("Please repeat the call giving its real name.\n") 399 sys.stderr.write("Please repeat the call giving its real name.\n")
374 sys.stderr.write("Ignoring the directory.\n") 400 sys.stderr.write("Ignoring the directory.\n")
375 continue 401 continue
376 else: 402 else:
377 basename = arg 403 basename = argsfile
378 if basename: 404 if basename:
379 basename = "{0}{1}".format(basename, os.sep) 405 basename = "{0}{1}".format(basename, os.sep)
380 406
381 if recursive and not os.path.islink(arg): 407 if recursive and not os.path.islink(argsfile):
382 names = [arg] + FileSystemUtilities.getDirs(arg, excludeDirs) 408 names = [argsfile] + FileSystemUtilities.getDirs(argsfile, excludeDirs)
383 else: 409 else:
384 names = [arg] 410 names = [argsfile]
385 else: 411 else:
386 basename = "" 412 basename = ""
387 names = [arg] 413 names = [argsfile]
388 414
389 for filename in names: 415 for filename in names:
390 inpackage = False 416 inpackage = False
391 if os.path.isdir(filename): 417 if os.path.isdir(filename):
392 files = [] 418 files = []

eric ide

mercurial