src/eric7/eric7_api.py

branch
eric7
changeset 10294
a055e1b82af8
parent 10065
de4ae767b0e3
child 10295
e0e7f81cc164
equal deleted inserted replaced
10293:6c5585c3e543 10294:a055e1b82af8
10 This is the main Python script of the API generator. It is 10 This is the main Python script of the API generator. It is
11 this script that gets called via the API generation interface. 11 this script that gets called via the API generation 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 sys 19 import sys
20 20
21 from eric7 import DocumentationTools 21 from eric7 import DocumentationTools
23 from eric7.SystemUtilities import FileSystemUtilities, OSUtilities 23 from eric7.SystemUtilities import FileSystemUtilities, OSUtilities
24 from eric7.UI.Info import Version 24 from eric7.UI.Info import Version
25 from eric7.Utilities import ModuleParser 25 from eric7.Utilities import ModuleParser
26 26
27 27
28 def usage(): 28 def createArgumentParser():
29 """ 29 """
30 Function to print some usage information. 30 Function to create an argument parser.
31 31
32 It prints a reference of all commandline parameters that may 32 @return created argument parser object
33 be used and ends the application. 33 @rtype argparse.ArgumentParser
34 """ 34 """
35 print("eric7_api") 35 parser = argparse.ArgumentParser(
36 print() 36 description=(
37 print("Copyright (c) 2004 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>.") 37 "Create API files to be used by 'QScintilla' or the 'eric Assistant'"
38 print() 38 " plugin."
39 print("Usage:") 39 ),
40 print() 40 epilog="Copyright (c) 2004 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>.",
41 print(" eric7_api [options] files...") 41 add_help=False,
42 print() 42 )
43 print("where files can be either python modules, package") 43
44 print("directories or ordinary directories.") 44 parser.add_argument(
45 print() 45 "file",
46 print("Options:") 46 nargs="*",
47 print() 47 help="'file' can be either python modules, package directories or ordinary"
48 print(" -b name or --base=name") 48 " directories.",
49 print(" Use the given name as the name of the base package.") 49 )
50 print(" -e eol-type or --eol=eol-type") 50 parser.add_argument(
51 print(" Use the given eol type to terminate lines.") 51 "-b",
52 print(" Valid values are 'cr', 'lf' and 'crlf'.") 52 "--base",
53 print(" --exclude-file=pattern") 53 default="",
54 print(" Specify a filename pattern of files to be excluded.") 54 help="Use the given name as the name of the base package.",
55 print(" This option may be repeated multiple times.") 55 )
56 print(" -h or --help") 56 parser.add_argument(
57 print(" Show this help and exit.") 57 "-e",
58 print(" -i or --ignore") 58 "--eol",
59 print(" Ignore the set of builtin modules") 59 choices=["cr", "lf", "crlf"],
60 print(" -l language or --language=language") 60 help="Use the given eol type to terminate lines.",
61 print(" Generate an API file for the given programming language.") 61 )
62 print(" Supported programming languages are:") 62 parser.add_argument(
63 for lang in sorted(DocumentationTools.supportedExtensionsDictForApis.keys()): 63 "--exclude-file",
64 print(" * {0}".format(lang)) 64 action="append",
65 print(" The default is 'Python3'.") 65 default=[],
66 print(" This option may be repeated multiple times.") 66 help="Specify a filename pattern of files to be excluded. This option may be"
67 print(" -o filename or --output=filename") 67 " repeated multiple times.",
68 print( 68 )
69 " Write the API information to the named file." 69 parser.add_argument(
70 " A '%L' placeholder" # __IGNORE_WARNING_M601__ 70 "-h", "--help", action="store_true", help="Show this help and exit."
71 ) 71 )
72 print(" is replaced by the language of the API file (see --language).") 72 parser.add_argument(
73 print(" -p or --private") 73 "-i",
74 print(" Include private methods and functions.") 74 "--ignore",
75 print(" -R, -r or --recursive") 75 action="store_true",
76 print(" Perform a recursive search for source files.") 76 help="Ignore the set of builtin modules.",
77 print(" -t ext or --extension=ext") 77 )
78 print(" Add the given extension to the list of file extensions.") 78 parser.add_argument(
79 print(" This option may be given multiple times.") 79 "-l",
80 print(" -V or --version") 80 "--language",
81 print(" Show version information and exit.") 81 action="append",
82 print(" -x directory or --exclude=directory") 82 default=[],
83 print(" Specify a directory basename to be excluded.") 83 choices=DocumentationTools.supportedExtensionsDictForApis.keys(),
84 print(" This option may be repeated multiple times.") 84 help="Generate an API file for the given programming language. The default"
85 sys.exit(1) 85 " is 'Python3'. This option may be repeated multiple times.",
86 )
87 parser.add_argument(
88 "-o",
89 "--output",
90 default="",
91 help="Write the API information to the named file. A '%%L'" # noqa: M601
92 " placeholder is replaced by the language of the API file (see --language).",
93 )
94 parser.add_argument(
95 "-p",
96 "--private",
97 action="store_true",
98 help="Include private methods and functions.",
99 )
100 parser.add_argument(
101 "-R",
102 "-r",
103 "--recursive",
104 action="store_true",
105 help="Perform a recursive search for source files.",
106 )
107 parser.add_argument(
108 "-t",
109 "--extension",
110 action="append",
111 default=[],
112 help="Add the given extension to the list of file extensions. This option may"
113 " be given multiple times.",
114 )
115 parser.add_argument(
116 "-V",
117 "--version",
118 action="store_true",
119 help="Show version information and exit.",
120 )
121 parser.add_argument(
122 "-x",
123 "--exclude",
124 action="append",
125 default=[],
126 help="Specify a directory basename to be excluded. This option may be repeated"
127 " multiple times.",
128 )
129
130 return parser
86 131
87 132
88 def version(): 133 def version():
89 """ 134 """
90 Function to show the version information. 135 Function to show the version information.
100 """ conditions.\n""" 145 """ conditions.\n"""
101 """There is NO warranty; not even for MERCHANTABILITY or FITNESS""" 146 """There is NO warranty; not even for MERCHANTABILITY or FITNESS"""
102 """ FOR A\n""" 147 """ FOR A\n"""
103 """PARTICULAR PURPOSE.""".format(Version) 148 """PARTICULAR PURPOSE.""".format(Version)
104 ) 149 )
105 sys.exit(1)
106 150
107 151
108 def main(): 152 def main():
109 """ 153 """
110 Main entry point into the application. 154 Main entry point into the application.
111 """ 155 """
112 global supportedExtensions 156 global supportedExtensions
113 157
114 try: 158 parser = createArgumentParser()
115 opts, args = getopt.getopt( 159 args = parser.parse_args()
116 sys.argv[1:], 160
117 "b:e:hil:o:pRrt:Vx:", 161 if args.help:
118 [ 162 parser.print_help()
119 "base=", 163 sys.exit(1)
120 "eol=", 164 elif args.version:
121 "exclude=", 165 version()
122 "exclude-file=", 166 sys.exit(1)
123 "extension=", 167
124 "help", 168 if not args.file:
125 "ignore", 169 parser.error(
126 "language=", 170 "At least one file, Python module, Python package or directory must be"
127 "output=", 171 " given."
128 "private",
129 "recursive",
130 "version",
131 ],
132 ) 172 )
133 except getopt.error: 173
134 usage() 174 if not args.output:
175 parser.error("No output file given.")
135 176
136 excludeDirs = [ 177 excludeDirs = [
137 ".svn", 178 ".svn",
138 ".hg", 179 ".hg",
139 ".git", 180 ".git",
141 ".eric7project", 182 ".eric7project",
142 "dist", 183 "dist",
143 "build", 184 "build",
144 "doc", 185 "doc",
145 "docs", 186 "docs",
187 ] + args.exclude
188 excludePatterns = args.exclude_file
189 outputFileName = args.output
190 recursive = args.recursive
191 basePackage = args.base
192 includePrivate = args.private
193 progLanguages = args.language
194 extensions = [
195 ext if ext.startswith(".") else ".{0}".format(ext) for ext in args.extension
146 ] 196 ]
147 excludePatterns = [] 197 ignoreBuiltinModules = args.ignore
148 outputFileName = "" 198 newline = {
149 recursive = False 199 "cr": "\r",
150 basePackage = "" 200 "lf": "\n",
151 includePrivate = False 201 "crlf": "\r\n",
152 progLanguages = [] 202 }[args.eol]
153 extensions = []
154 newline = None
155 ignoreBuiltinModules = False
156
157 for k, v in opts:
158 if k in ["-o", "--output"]:
159 outputFileName = v
160 elif k in ["-R", "-r", "--recursive"]:
161 recursive = True
162 elif k in ["-x", "--exclude"]:
163 excludeDirs.append(v)
164 elif k == "--exclude-file":
165 excludePatterns.append(v)
166 elif k in ["-h", "--help"]:
167 usage()
168 elif k in ["-i", "--ignore"]:
169 ignoreBuiltinModules = True
170 elif k in ["-V", "--version"]:
171 version()
172 elif k in ["-t", "--extension"]:
173 if not v.startswith("."):
174 v = ".{0}".format(v)
175 extensions.append(v)
176 elif k in ["-b", "--base"]:
177 basePackage = v
178 elif k in ["-p", "--private"]:
179 includePrivate = True
180 elif k in ["-l", "--language"]:
181 if v not in progLanguages:
182 if v not in DocumentationTools.supportedExtensionsDictForApis:
183 sys.stderr.write("Wrong language given: {0}. Aborting\n".format(v))
184 sys.exit(1)
185 else:
186 progLanguages.append(v)
187 elif k in ["-e", "--eol"]:
188 if v.lower() == "cr":
189 newline = "\r"
190 elif v.lower() == "lf":
191 newline = "\n"
192 elif v.lower() == "crlf":
193 newline = "\r\n"
194
195 if not args:
196 usage()
197
198 if outputFileName == "":
199 sys.stderr.write("No output file given. Aborting\n")
200 sys.exit(1)
201 203
202 if len(progLanguages) == 0: 204 if len(progLanguages) == 0:
203 progLanguages = ["Python3"] 205 progLanguages = ["Python3"]
204 206
205 for progLanguage in sorted(progLanguages): 207 for progLanguage in sorted(progLanguages):
225 else: 227 else:
226 root, ext = os.path.splitext(outputFileName) 228 root, ext = os.path.splitext(outputFileName)
227 outputFile = "{0}-{1}{2}".format(root, progLanguage.lower(), ext) 229 outputFile = "{0}-{1}{2}".format(root, progLanguage.lower(), ext)
228 basesFile = os.path.splitext(outputFile)[0] + ".bas" 230 basesFile = os.path.splitext(outputFile)[0] + ".bas"
229 231
230 for arg in args: 232 for argsfile in args.file:
231 if os.path.isdir(arg): 233 if os.path.isdir(argsfile):
232 if os.path.exists( 234 if os.path.exists(
233 os.path.join(arg, FileSystemUtilities.joinext("__init__", ".py")) 235 os.path.join(
236 argsfile, FileSystemUtilities.joinext("__init__", ".py")
237 )
234 ): 238 ):
235 basename = os.path.dirname(arg) 239 basename = os.path.dirname(argsfile)
236 if arg == ".": 240 if argsfile == ".":
237 sys.stderr.write("The directory '.' is a package.\n") 241 sys.stderr.write("The directory '.' is a package.\n")
238 sys.stderr.write( 242 sys.stderr.write(
239 "Please repeat the call giving its real name.\n" 243 "Please repeat the call giving its real name.\n"
240 ) 244 )
241 sys.stderr.write("Ignoring the directory.\n") 245 sys.stderr.write("Ignoring the directory.\n")
242 continue 246 continue
243 else: 247 else:
244 basename = arg 248 basename = argsfile
245 if basename: 249 if basename:
246 basename = "{0}{1}".format(basename, os.sep) 250 basename = "{0}{1}".format(basename, os.sep)
247 251
248 if recursive and not os.path.islink(arg): 252 if recursive and not os.path.islink(argsfile):
249 names = [arg] + FileSystemUtilities.getDirs(arg, excludeDirs) 253 names = [argsfile] + FileSystemUtilities.getDirs(
254 argsfile, excludeDirs
255 )
250 else: 256 else:
251 names = [arg] 257 names = [argsfile]
252 else: 258 else:
253 basename = "" 259 basename = ""
254 names = [arg] 260 names = [argsfile]
255 261
256 for filename in sorted(names): 262 for filename in sorted(names):
257 inpackage = False 263 inpackage = False
258 if os.path.isdir(filename): 264 if os.path.isdir(filename):
259 files = [] 265 files = []

eric ide

mercurial