eric6_api.py

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

eric ide

mercurial