File: Synopsis/Parsers/Python/__init__.py 1
2
3
4
5
6
7
8from Synopsis.Processor import *
9from Synopsis import ASG
10from Synopsis.QualifiedName import QualifiedPythonName as QName
11from Synopsis.SourceFile import SourceFile
12from Synopsis.DocString import DocString
13from ASGTranslator import ASGTranslator
14from SXRGenerator import SXRGenerator
15import os
16
17__all__ = ['Parser']
18
19def expand_package(root, verbose = False):
20 """Find all modules in a given package."""
21
22 modules = []
23 if not os.path.isdir(root) or not os.path.isfile(os.path.join(root, '__init__.py')):
24 return modules
25 if verbose: print 'expanding %s'%root
26 files = os.listdir(root)
27 modules += [os.path.join(root, file)
28 for file in files if os.path.splitext(file)[1] == '.py']
29 for d in [dir for dir in files if os.path.isdir(os.path.join(root, dir))]:
30 modules.extend(expand_package(os.path.join(root, d), verbose))
31 return modules
32
33
34def find_imported(target, base_path, origin, verbose = False):
35 """
36 Lookup imported files, based on current file's location.
37
38 target: (module, name) pair.
39 base_path: root directory to which to confine the lookup.
40 origin: file name of the module issuing the import."""
41
42 module, name = target[0].replace('.', os.sep), target[1]
43 origin = os.path.dirname(origin)
44 if base_path:
45 locations = [base_path + origin.rsplit(os.sep, i)[0]
46 for i in range(origin.count(os.sep) + 1)] + [base_path]
47 else:
48 locations = [origin]
49
50
51 if name and name != '*':
52
53
54 files = ['%s/%s.py'%(module, name), '%s.py'%module]
55 else:
56 files = ['%s.py'%module]
57 files.append(os.path.join(module, '__init__.py'))
58 for l in locations:
59 for f in files:
60 target = os.path.join(l, f)
61 if verbose: print 'trying %s'%target
62 if os.path.exists(target):
63 return target, target[len(base_path):]
64 return None, None
65
66
67
68class Parser(Processor):
69 """
70 Python Parser. See http://www.python.org/dev/peps/pep-0258 for additional
71 info."""
72
73 primary_file_only = Parameter(True, 'should only primary file be processed')
74 base_path = Parameter(None, 'Path prefix to strip off of input file names.')
75 sxr_prefix = Parameter(None, 'Path prefix (directory) to contain sxr info.')
76 default_docformat = Parameter('', 'default documentation format')
77
78 def process(self, ir, **kwds):
79
80 self.set_parameters(kwds)
81 if not self.input: raise MissingArgument('input')
82 self.ir = ir
83 self.scopes = []
84
85
86 self.return_type = ASG.BuiltinTypeId('Python',('',))
87
88
89 if self.base_path:
90 if not os.path.isdir(self.base_path):
91 raise InvalidArgument('base_path: "%s" not a directory.'
92 %self.base_path)
93 if self.base_path[-1] != os.sep:
94 self.base_path += os.sep
95
96
97
98
99
100
101 self.all_files = []
102 for i in self.input:
103 base_path = self.base_path or os.path.dirname(i)
104 if base_path and base_path[-1] != os.sep:
105 base_path += os.sep
106
107 if os.path.isdir(i):
108 if os.path.exists(os.path.join(i, '__init__.py')):
109 self.all_files.extend([(p,base_path)
110 for p in expand_package(i, self.verbose)])
111 else:
112 raise InvalidArgument('"%s" is not a Python package'%i)
113 else:
114 self.all_files.append((i,base_path))
115
116 while len(self.all_files):
117 file, base_path = self.all_files.pop()
118 self.process_file(file, base_path)
119
120 return self.output_and_return_ir()
121
122
123 def process_file(self, filename, base_path):
124 """Parse an individual python file."""
125
126 long_filename = filename
127 if filename[:len(base_path)] != base_path:
128 raise InvalidArgument('invalid input filename:\n'
129 '"%s" does not match base_path "%s"'
130 %(filename, base_path))
131 if self.verbose: print 'parsing %s'%filename
132 short_filename = filename[len(base_path):]
133 sourcefile = SourceFile(short_filename, long_filename, 'Python', True)
134 self.ir.files[short_filename] = sourcefile
135
136 package = None
137 package_name = []
138 package_path = base_path
139
140 if package_path != filename:
141 components = short_filename.split(os.sep)
142 if components[0] == '':
143 package_path += os.sep
144 components = components[1:]
145 for c in components[:-1]:
146 package_name.append(c)
147 package_path = os.path.join(package_path, c)
148 qname = QName(package_name)
149 if not os.path.isfile(os.path.join(package_path, '__init__.py')):
150 raise InvalidArgument('"%s" is not a package'%qname)
151
152 type_id = self.ir.asg.types.get(qname)
153 if (type_id):
154 module = type_id.declaration
155 else:
156 module = ASG.Module(sourcefile, -1, 'package', qname)
157 self.ir.asg.types[qname] = ASG.DeclaredTypeId('Python', qname, module)
158 if package:
159 package.declarations.append(module)
160 else:
161 self.ir.asg.declarations.append(module)
162
163 package = module
164
165 translator = ASGTranslator(package, self.ir.asg.types, self.default_docformat)
166 translator.process_file(sourcefile)
167
168 if package:
169 package.declarations.extend(sourcefile.declarations)
170 else:
171 self.ir.asg.declarations.extend(sourcefile.declarations)
172 if not self.primary_file_only:
173 for i in translator.imports:
174 target = find_imported(i, self.base_path, sourcefile.name, self.verbose)
175 if target[0] and target[1] not in self.ir.files:
176
177 self.all_files.append((target[0], base_path))
178
179 if self.sxr_prefix:
180 sxr = os.path.join(self.sxr_prefix, short_filename + '.sxr')
181 dirname = os.path.dirname(sxr)
182 if not os.path.exists(dirname):
183 os.makedirs(dirname, 0755)
184
185 sxr_generator = SXRGenerator()
186 module = sourcefile.declarations[0]
187 sxr_generator.process_file(module.name, sourcefile, sxr)
188
Generated on Thu Apr 16 16:27:15 2009 by
synopsis (version devel)