eric6/eric6_api.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 6949
a5255f1ba3f0
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 # Copyright (c) 2003 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
5 #
6
7 """
8 Eric6 API Generator.
9
10 This is the main Python script of the API generator. It is
11 this script that gets called via the API generation interface.
12 This script can be used via the commandline as well.
13 """
14
15 from __future__ import unicode_literals
16
17 import Toolbox.PyQt4ImportHook # __IGNORE_WARNING__
18
19 try: # Only for Py2
20 import Globals.compatibility_fixes # __IGNORE_WARNING__
21 except (ImportError):
22 pass
23
24 import glob
25 import os
26 import sys
27 import fnmatch
28
29 # make ThirdParty package available as a packages repository
30 sys.path.insert(2, os.path.join(os.path.dirname(__file__),
31 "ThirdParty", "EditorConfig"))
32
33 import Utilities.ModuleParser
34 from DocumentationTools.APIGenerator import APIGenerator
35 from UI.Info import Version
36 import Utilities
37 import DocumentationTools
38
39
40 def usage():
41 """
42 Function to print some usage information.
43
44 It prints a reference of all commandline parameters that may
45 be used and ends the application.
46 """
47 print("eric6_api")
48 print()
49 print("Copyright (c) 2004 - 2019 Detlev Offenbach"
50 " <detlev@die-offenbachs.de>.")
51 print()
52 print("Usage:")
53 print()
54 print(" eric6_api [options] files...")
55 print()
56 print("where files can be either python modules, package")
57 print("directories or ordinary directories.")
58 print()
59 print("Options:")
60 print()
61 print(" -b name or --base=name")
62 print(" Use the given name as the name of the base package.")
63 print(" -e eol-type or --eol=eol-type")
64 print(" Use the given eol type to terminate lines.")
65 print(" Valid values are 'cr', 'lf' and 'crlf'.")
66 print(" --exclude-file=pattern")
67 print(" Specify a filename pattern of files to be excluded.")
68 print(" This option may be repeated multiple times.")
69 print(" -h or --help")
70 print(" Show this help and exit.")
71 print(" -l language or --language=language")
72 print(" Generate an API file for the given programming language.")
73 print(" Supported programming languages are:")
74 for lang in sorted(
75 DocumentationTools.supportedExtensionsDictForApis.keys()):
76 print(" * {0}".format(lang))
77 print(" The default is 'Python3'.")
78 print(" This option may be repeated multiple times.")
79 print(" -o filename or --output=filename")
80 print(" Write the API information to the named file."
81 " A '%L' placeholder") # __IGNORE_WARNING_M601__
82 print(" is replaced by the language of the API file"
83 " (see --language).")
84 print(" -p or --private")
85 print(" Include private methods and functions.")
86 print(" -R, -r or --recursive")
87 print(" Perform a recursive search for source files.")
88 print(" -t ext or --extension=ext")
89 print(" Add the given extension to the list of file extensions.")
90 print(" This option may be given multiple times.")
91 print(" -V or --version")
92 print(" Show version information and exit.")
93 print(" -x directory or --exclude=directory")
94 print(" Specify a directory basename to be excluded.")
95 print(" This option may be repeated multiple times.")
96 sys.exit(1)
97
98
99 def version():
100 """
101 Function to show the version information.
102 """
103 print(
104 """eric6_api {0}\n"""
105 """\n"""
106 """Eric6 API generator.\n"""
107 """\n"""
108 """Copyright (c) 2004 - 2019 Detlev Offenbach"""
109 """ <detlev@die-offenbachs.de>\n"""
110 """This is free software; see the LICENSE.GPL3 for copying"""
111 """ conditions.\n"""
112 """There is NO warranty; not even for MERCHANTABILITY or FITNESS"""
113 """ FOR A\n"""
114 """PARTICULAR PURPOSE.""".format(Version))
115 sys.exit(1)
116
117
118 def main():
119 """
120 Main entry point into the application.
121 """
122 global supportedExtensions
123
124 import getopt
125
126 try:
127 opts, args = getopt.getopt(
128 sys.argv[1:], "b:e:hl:o:pRrt:Vx:",
129 ["base=", "eol=", "exclude=", "exclude-file=", "extension=",
130 "help", "language=", "output=", "private", "recursive",
131 "version", ])
132 except getopt.error:
133 usage()
134
135 excludeDirs = [".svn", ".hg", ".git", ".ropeproject", ".eric6project",
136 "dist", "build", "doc", "docs"]
137 excludePatterns = []
138 outputFileName = ""
139 recursive = False
140 basePackage = ""
141 includePrivate = False
142 progLanguages = []
143 extensions = []
144 newline = None
145
146 for k, v in opts:
147 if k in ["-o", "--output"]:
148 outputFileName = v
149 elif k in ["-R", "-r", "--recursive"]:
150 recursive = True
151 elif k in ["-x", "--exclude"]:
152 excludeDirs.append(v)
153 elif k == "--exclude-file":
154 excludePatterns.append(v)
155 elif k in ["-h", "--help"]:
156 usage()
157 elif k in ["-V", "--version"]:
158 version()
159 elif k in ["-t", "--extension"]:
160 if not v.startswith("."):
161 v = ".{0}".format(v)
162 extensions.append(v)
163 elif k in ["-b", "--base"]:
164 basePackage = v
165 elif k in ["-p", "--private"]:
166 includePrivate = True
167 elif k in ["-l", "--language"]:
168 if v not in progLanguages:
169 if v not in \
170 DocumentationTools.supportedExtensionsDictForApis:
171 sys.stderr.write(
172 "Wrong language given: {0}. Aborting\n".format(v))
173 sys.exit(1)
174 else:
175 progLanguages.append(v)
176 elif k in ["-e", "--eol"]:
177 if v.lower() == "cr":
178 newline = '\r'
179 elif v.lower() == "lf":
180 newline = '\n'
181 elif v.lower() == "crlf":
182 newline = '\r\n'
183
184 if not args:
185 usage()
186
187 if outputFileName == "":
188 sys.stderr.write("No output file given. Aborting\n")
189 sys.exit(1)
190
191 if len(progLanguages) == 0:
192 progLanguages = ["Python3"]
193
194 for progLanguage in sorted(progLanguages):
195 basename = ""
196 apis = []
197 basesDict = {}
198
199 supportedExtensions = \
200 DocumentationTools.supportedExtensionsDictForApis[progLanguage]
201 supportedExtensions.extend(extensions)
202 if "%L" in outputFileName:
203 outputFile = outputFileName.replace("%L", progLanguage)
204 else:
205 if len(progLanguages) == 1:
206 outputFile = outputFileName
207 else:
208 root, ext = os.path.splitext(outputFileName)
209 outputFile = "{0}-{1}{2}".format(root, progLanguage.lower(),
210 ext)
211 basesFile = os.path.splitext(outputFile)[0] + '.bas'
212
213 for arg in args:
214 if os.path.isdir(arg):
215 if os.path.exists(os.path.join(
216 arg, Utilities.joinext("__init__", ".py"))):
217 basename = os.path.dirname(arg)
218 if arg == '.':
219 sys.stderr.write("The directory '.' is a package.\n")
220 sys.stderr.write(
221 "Please repeat the call giving its real name.\n")
222 sys.stderr.write("Ignoring the directory.\n")
223 continue
224 else:
225 basename = arg
226 if basename:
227 basename = "{0}{1}".format(basename, os.sep)
228
229 if recursive and not os.path.islink(arg):
230 names = [arg] + Utilities.getDirs(arg, excludeDirs)
231 else:
232 names = [arg]
233 else:
234 basename = ""
235 names = [arg]
236
237 for filename in sorted(names):
238 inpackage = False
239 if os.path.isdir(filename):
240 files = []
241 for ext in supportedExtensions:
242 files.extend(glob.glob(os.path.join(
243 filename, Utilities.joinext("*", ext))))
244 initFile = os.path.join(
245 filename, Utilities.joinext("__init__", ext))
246 if initFile in files:
247 inpackage = True
248 files.remove(initFile)
249 files.insert(0, initFile)
250 elif progLanguage != "Python3":
251 # assume package
252 inpackage = True
253 else:
254 if Utilities.isWindowsPlatform() and \
255 glob.has_magic(filename):
256 files = glob.glob(filename)
257 else:
258 files = [filename]
259
260 for file in files:
261 skipIt = False
262 for pattern in excludePatterns:
263 if fnmatch.fnmatch(os.path.basename(file), pattern):
264 skipIt = True
265 break
266 if skipIt:
267 continue
268
269 try:
270 module = Utilities.ModuleParser.readModule(
271 file,
272 basename=basename, inpackage=inpackage)
273 apiGenerator = APIGenerator(module)
274 api = apiGenerator.genAPI(True, basePackage,
275 includePrivate)
276 bases = apiGenerator.genBases(includePrivate)
277 except IOError as v:
278 sys.stderr.write("{0} error: {1}\n".format(file, v[1]))
279 continue
280 except ImportError as v:
281 sys.stderr.write("{0} error: {1}\n".format(file, v))
282 continue
283
284 for apiEntry in api:
285 if apiEntry not in apis:
286 apis.append(apiEntry)
287 for basesEntry in bases:
288 if bases[basesEntry]:
289 basesDict[basesEntry] = bases[basesEntry][:]
290 sys.stdout.write("-- {0} -- {1} ok\n".format(
291 progLanguage, file))
292
293 outdir = os.path.dirname(outputFile)
294 if outdir and not os.path.exists(outdir):
295 os.makedirs(outdir)
296 try:
297 out = open(outputFile, "w", encoding="utf-8", newline=newline)
298 out.write("\n".join(sorted(apis)) + "\n")
299 out.close()
300 except IOError as v:
301 sys.stderr.write("{0} error: {1}\n".format(outputFile, v[1]))
302 sys.exit(3)
303 try:
304 out = open(basesFile, "w", encoding="utf-8", newline=newline)
305 for baseEntry in sorted(basesDict.keys()):
306 out.write("{0} {1}\n".format(
307 baseEntry, " ".join(sorted(basesDict[baseEntry]))))
308 out.close()
309 except IOError as v:
310 sys.stderr.write("{0} error: {1}\n".format(basesFile, v[1]))
311 sys.exit(3)
312
313 sys.stdout.write('\nDone.\n')
314 sys.exit(0)
315
316 if __name__ == '__main__':
317 main()
318
319 #
320 # eflag: noqa = M801

eric ide

mercurial