src/eric7/eric7_api.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9364
83dea9e54ff4
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
27 27
28 28
29 def usage(): 29 def usage():
30 """ 30 """
31 Function to print some usage information. 31 Function to print some usage information.
32 32
33 It prints a reference of all commandline parameters that may 33 It prints a reference of all commandline parameters that may
34 be used and ends the application. 34 be used and ends the application.
35 """ 35 """
36 print("eric7_api") 36 print("eric7_api")
37 print() 37 print()
38 print("Copyright (c) 2004 - 2022 Detlev Offenbach" 38 print("Copyright (c) 2004 - 2022 Detlev Offenbach" " <detlev@die-offenbachs.de>.")
39 " <detlev@die-offenbachs.de>.")
40 print() 39 print()
41 print("Usage:") 40 print("Usage:")
42 print() 41 print()
43 print(" eric7_api [options] files...") 42 print(" eric7_api [options] files...")
44 print() 43 print()
60 print(" -i or --ignore") 59 print(" -i or --ignore")
61 print(" Ignore the set of builtin modules") 60 print(" Ignore the set of builtin modules")
62 print(" -l language or --language=language") 61 print(" -l language or --language=language")
63 print(" Generate an API file for the given programming language.") 62 print(" Generate an API file for the given programming language.")
64 print(" Supported programming languages are:") 63 print(" Supported programming languages are:")
65 for lang in sorted( 64 for lang in sorted(DocumentationTools.supportedExtensionsDictForApis.keys()):
66 DocumentationTools.supportedExtensionsDictForApis.keys()):
67 print(" * {0}".format(lang)) 65 print(" * {0}".format(lang))
68 print(" The default is 'Python3'.") 66 print(" The default is 'Python3'.")
69 print(" This option may be repeated multiple times.") 67 print(" This option may be repeated multiple times.")
70 print(" -o filename or --output=filename") 68 print(" -o filename or --output=filename")
71 print(" Write the API information to the named file." 69 print(
72 " A '%L' placeholder") # __IGNORE_WARNING_M601__ 70 " Write the API information to the named file."
73 print(" is replaced by the language of the API file" 71 " A '%L' placeholder" # __IGNORE_WARNING_M601__
74 " (see --language).") 72 )
73 print(" is replaced by the language of the API file" " (see --language).")
75 print(" -p or --private") 74 print(" -p or --private")
76 print(" Include private methods and functions.") 75 print(" Include private methods and functions.")
77 print(" -R, -r or --recursive") 76 print(" -R, -r or --recursive")
78 print(" Perform a recursive search for source files.") 77 print(" Perform a recursive search for source files.")
79 print(" -t ext or --extension=ext") 78 print(" -t ext or --extension=ext")
100 """ <detlev@die-offenbachs.de>\n""" 99 """ <detlev@die-offenbachs.de>\n"""
101 """This is free software; see the LICENSE.GPL3 for copying""" 100 """This is free software; see the LICENSE.GPL3 for copying"""
102 """ conditions.\n""" 101 """ conditions.\n"""
103 """There is NO warranty; not even for MERCHANTABILITY or FITNESS""" 102 """There is NO warranty; not even for MERCHANTABILITY or FITNESS"""
104 """ FOR A\n""" 103 """ FOR A\n"""
105 """PARTICULAR PURPOSE.""".format(Version)) 104 """PARTICULAR PURPOSE.""".format(Version)
105 )
106 sys.exit(1) 106 sys.exit(1)
107 107
108 108
109 def main(): 109 def main():
110 """ 110 """
111 Main entry point into the application. 111 Main entry point into the application.
112 """ 112 """
113 global supportedExtensions 113 global supportedExtensions
114 114
115 import getopt 115 import getopt
116 116
117 try: 117 try:
118 opts, args = getopt.getopt( 118 opts, args = getopt.getopt(
119 sys.argv[1:], "b:e:hil:o:pRrt:Vx:", 119 sys.argv[1:],
120 ["base=", "eol=", "exclude=", "exclude-file=", "extension=", 120 "b:e:hil:o:pRrt:Vx:",
121 "help", "ignore", "language=", "output=", "private", "recursive", 121 [
122 "version", ]) 122 "base=",
123 "eol=",
124 "exclude=",
125 "exclude-file=",
126 "extension=",
127 "help",
128 "ignore",
129 "language=",
130 "output=",
131 "private",
132 "recursive",
133 "version",
134 ],
135 )
123 except getopt.error: 136 except getopt.error:
124 usage() 137 usage()
125 138
126 excludeDirs = [".svn", ".hg", ".git", ".ropeproject", ".eric7project", 139 excludeDirs = [
127 "dist", "build", "doc", "docs"] 140 ".svn",
141 ".hg",
142 ".git",
143 ".ropeproject",
144 ".eric7project",
145 "dist",
146 "build",
147 "doc",
148 "docs",
149 ]
128 excludePatterns = [] 150 excludePatterns = []
129 outputFileName = "" 151 outputFileName = ""
130 recursive = False 152 recursive = False
131 basePackage = "" 153 basePackage = ""
132 includePrivate = False 154 includePrivate = False
159 elif k in ["-p", "--private"]: 181 elif k in ["-p", "--private"]:
160 includePrivate = True 182 includePrivate = True
161 elif k in ["-l", "--language"]: 183 elif k in ["-l", "--language"]:
162 if v not in progLanguages: 184 if v not in progLanguages:
163 if v not in DocumentationTools.supportedExtensionsDictForApis: 185 if v not in DocumentationTools.supportedExtensionsDictForApis:
164 sys.stderr.write( 186 sys.stderr.write("Wrong language given: {0}. Aborting\n".format(v))
165 "Wrong language given: {0}. Aborting\n".format(v))
166 sys.exit(1) 187 sys.exit(1)
167 else: 188 else:
168 progLanguages.append(v) 189 progLanguages.append(v)
169 elif k in ["-e", "--eol"]: 190 elif k in ["-e", "--eol"]:
170 if v.lower() == "cr": 191 if v.lower() == "cr":
171 newline = '\r' 192 newline = "\r"
172 elif v.lower() == "lf": 193 elif v.lower() == "lf":
173 newline = '\n' 194 newline = "\n"
174 elif v.lower() == "crlf": 195 elif v.lower() == "crlf":
175 newline = '\r\n' 196 newline = "\r\n"
176 197
177 if not args: 198 if not args:
178 usage() 199 usage()
179 200
180 if outputFileName == "": 201 if outputFileName == "":
181 sys.stderr.write("No output file given. Aborting\n") 202 sys.stderr.write("No output file given. Aborting\n")
182 sys.exit(1) 203 sys.exit(1)
183 204
184 if len(progLanguages) == 0: 205 if len(progLanguages) == 0:
185 progLanguages = ["Python3"] 206 progLanguages = ["Python3"]
186 207
187 for progLanguage in sorted(progLanguages): 208 for progLanguage in sorted(progLanguages):
188 basename = "" 209 basename = ""
189 apis = [] 210 apis = []
190 basesDict = {} 211 basesDict = {}
191 212
192 supportedExtensions = ( 213 supportedExtensions = DocumentationTools.supportedExtensionsDictForApis[
193 DocumentationTools.supportedExtensionsDictForApis[progLanguage] 214 progLanguage
194 ) 215 ]
195 supportedExtensions.extend(extensions) 216 supportedExtensions.extend(extensions)
196 217
197 if not outputFileName.endswith(".api"): 218 if not outputFileName.endswith(".api"):
198 # append the .api extension, if not given by the user 219 # append the .api extension, if not given by the user
199 outputFileName += ".api" 220 outputFileName += ".api"
200 if "%L" in outputFileName: 221 if "%L" in outputFileName:
201 outputFile = outputFileName.replace("%L", progLanguage) 222 outputFile = outputFileName.replace("%L", progLanguage)
202 else: 223 else:
203 if len(progLanguages) == 1: 224 if len(progLanguages) == 1:
204 outputFile = outputFileName 225 outputFile = outputFileName
205 else: 226 else:
206 root, ext = os.path.splitext(outputFileName) 227 root, ext = os.path.splitext(outputFileName)
207 outputFile = "{0}-{1}{2}".format(root, progLanguage.lower(), 228 outputFile = "{0}-{1}{2}".format(root, progLanguage.lower(), ext)
208 ext) 229 basesFile = os.path.splitext(outputFile)[0] + ".bas"
209 basesFile = os.path.splitext(outputFile)[0] + '.bas' 230
210
211 for arg in args: 231 for arg in args:
212 if os.path.isdir(arg): 232 if os.path.isdir(arg):
213 if os.path.exists(os.path.join( 233 if os.path.exists(
214 arg, Utilities.joinext("__init__", ".py"))): 234 os.path.join(arg, Utilities.joinext("__init__", ".py"))
235 ):
215 basename = os.path.dirname(arg) 236 basename = os.path.dirname(arg)
216 if arg == '.': 237 if arg == ".":
217 sys.stderr.write("The directory '.' is a package.\n") 238 sys.stderr.write("The directory '.' is a package.\n")
218 sys.stderr.write( 239 sys.stderr.write(
219 "Please repeat the call giving its real name.\n") 240 "Please repeat the call giving its real name.\n"
241 )
220 sys.stderr.write("Ignoring the directory.\n") 242 sys.stderr.write("Ignoring the directory.\n")
221 continue 243 continue
222 else: 244 else:
223 basename = arg 245 basename = arg
224 if basename: 246 if basename:
225 basename = "{0}{1}".format(basename, os.sep) 247 basename = "{0}{1}".format(basename, os.sep)
226 248
227 if recursive and not os.path.islink(arg): 249 if recursive and not os.path.islink(arg):
228 names = [arg] + Utilities.getDirs(arg, excludeDirs) 250 names = [arg] + Utilities.getDirs(arg, excludeDirs)
229 else: 251 else:
230 names = [arg] 252 names = [arg]
231 else: 253 else:
232 basename = "" 254 basename = ""
233 names = [arg] 255 names = [arg]
234 256
235 for filename in sorted(names): 257 for filename in sorted(names):
236 inpackage = False 258 inpackage = False
237 if os.path.isdir(filename): 259 if os.path.isdir(filename):
238 files = [] 260 files = []
239 for ext in supportedExtensions: 261 for ext in supportedExtensions:
240 files.extend(glob.glob(os.path.join( 262 files.extend(
241 filename, Utilities.joinext("*", ext)))) 263 glob.glob(
264 os.path.join(filename, Utilities.joinext("*", ext))
265 )
266 )
242 initFile = os.path.join( 267 initFile = os.path.join(
243 filename, Utilities.joinext("__init__", ext)) 268 filename, Utilities.joinext("__init__", ext)
269 )
244 if initFile in files: 270 if initFile in files:
245 inpackage = True 271 inpackage = True
246 files.remove(initFile) 272 files.remove(initFile)
247 files.insert(0, initFile) 273 files.insert(0, initFile)
248 elif progLanguage != "Python3": 274 elif progLanguage != "Python3":
249 # assume package 275 # assume package
250 inpackage = True 276 inpackage = True
251 else: 277 else:
252 if ( 278 if Utilities.isWindowsPlatform() and glob.has_magic(filename):
253 Utilities.isWindowsPlatform() and
254 glob.has_magic(filename)
255 ):
256 files = glob.glob(filename) 279 files = glob.glob(filename)
257 else: 280 else:
258 files = [filename] 281 files = [filename]
259 282
260 for file in files: 283 for file in files:
261 skipIt = False 284 skipIt = False
262 for pattern in excludePatterns: 285 for pattern in excludePatterns:
263 if fnmatch.fnmatch(os.path.basename(file), pattern): 286 if fnmatch.fnmatch(os.path.basename(file), pattern):
264 skipIt = True 287 skipIt = True
265 break 288 break
266 if skipIt: 289 if skipIt:
267 continue 290 continue
268 291
269 try: 292 try:
270 module = Utilities.ModuleParser.readModule( 293 module = Utilities.ModuleParser.readModule(
271 file, 294 file,
272 basename=basename, inpackage=inpackage, 295 basename=basename,
273 ignoreBuiltinModules=ignoreBuiltinModules) 296 inpackage=inpackage,
297 ignoreBuiltinModules=ignoreBuiltinModules,
298 )
274 apiGenerator = APIGenerator(module) 299 apiGenerator = APIGenerator(module)
275 api = apiGenerator.genAPI(True, basePackage, 300 api = apiGenerator.genAPI(True, basePackage, includePrivate)
276 includePrivate)
277 bases = apiGenerator.genBases(includePrivate) 301 bases = apiGenerator.genBases(includePrivate)
278 except OSError as v: 302 except OSError as v:
279 sys.stderr.write("{0} error: {1}\n".format(file, v[1])) 303 sys.stderr.write("{0} error: {1}\n".format(file, v[1]))
280 continue 304 continue
281 except ImportError as v: 305 except ImportError as v:
282 sys.stderr.write("{0} error: {1}\n".format(file, v)) 306 sys.stderr.write("{0} error: {1}\n".format(file, v))
283 continue 307 continue
284 308
285 for apiEntry in api: 309 for apiEntry in api:
286 if apiEntry not in apis: 310 if apiEntry not in apis:
287 apis.append(apiEntry) 311 apis.append(apiEntry)
288 for basesEntry in bases: 312 for basesEntry in bases:
289 if bases[basesEntry]: 313 if bases[basesEntry]:
290 basesDict[basesEntry] = bases[basesEntry][:] 314 basesDict[basesEntry] = bases[basesEntry][:]
291 sys.stdout.write("-- {0} -- {1} ok\n".format( 315 sys.stdout.write("-- {0} -- {1} ok\n".format(progLanguage, file))
292 progLanguage, file))
293 316
294 outdir = os.path.dirname(outputFile) 317 outdir = os.path.dirname(outputFile)
295 if outdir and not os.path.exists(outdir): 318 if outdir and not os.path.exists(outdir):
296 os.makedirs(outdir) 319 os.makedirs(outdir)
297 try: 320 try:
298 with open(outputFile, "w", encoding="utf-8", 321 with open(outputFile, "w", encoding="utf-8", newline=newline) as out:
299 newline=newline) as out:
300 out.write("\n".join(sorted(apis)) + "\n") 322 out.write("\n".join(sorted(apis)) + "\n")
301 except OSError as v: 323 except OSError as v:
302 sys.stderr.write("{0} error: {1}\n".format(outputFile, v[1])) 324 sys.stderr.write("{0} error: {1}\n".format(outputFile, v[1]))
303 sys.exit(3) 325 sys.exit(3)
304 try: 326 try:
305 with open(basesFile, "w", encoding="utf-8", 327 with open(basesFile, "w", encoding="utf-8", newline=newline) as out:
306 newline=newline) as out:
307 for baseEntry in sorted(basesDict.keys()): 328 for baseEntry in sorted(basesDict.keys()):
308 out.write("{0} {1}\n".format( 329 out.write(
309 baseEntry, " ".join(sorted(basesDict[baseEntry])))) 330 "{0} {1}\n".format(
331 baseEntry, " ".join(sorted(basesDict[baseEntry]))
332 )
333 )
310 except OSError as v: 334 except OSError as v:
311 sys.stderr.write("{0} error: {1}\n".format(basesFile, v[1])) 335 sys.stderr.write("{0} error: {1}\n".format(basesFile, v[1]))
312 sys.exit(3) 336 sys.exit(3)
313 337
314 sys.stdout.write('\nDone.\n') 338 sys.stdout.write("\nDone.\n")
315 sys.exit(0) 339 sys.exit(0)
316 340
317 if __name__ == '__main__': 341
342 if __name__ == "__main__":
318 main() 343 main()
319 344
320 # 345 #
321 # eflag: noqa = M801 346 # eflag: noqa = M801

eric ide

mercurial