1 #!/usr/bin/env python 2 3 """ 4 The simplify package for processing Python source code. 5 6 Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 21 -------- 22 23 To use this module, an importer should be constructed and the load_from_file 24 method used. Here, the standard path for module searching is employed: 25 26 importer = Importer(sys.path) 27 importer.load_from_file(builtins) 28 importer.load_from_file(filename, builtins) 29 """ 30 31 from simplify.simplified import * 32 import simplify.ast 33 import simplify.fixnames 34 import simplify.annotate 35 import simplify.fixinstances 36 37 class Importer: 38 39 "An import machine, searching for and loading modules." 40 41 def __init__(self, path=None, annotate=1, fixinstances=1): 42 43 """ 44 Initialise the importer with the given search 'path' - a list of 45 directories to search for Python modules. If the optional 'annotate' 46 parameter is set to a false value (unlike the default), no annotation 47 will be performed. 48 false value (unlike the default), no instance fixing will be performed. 49 """ 50 51 self.path = path or [os.getcwd()] 52 self.path.append(libdir) 53 self.annotate = annotate 54 self.modules = {} 55 56 def get_modules(self): 57 58 "Return all modules known to the importer." 59 60 return self.modules.values() 61 62 def find_in_path(self, name): 63 64 """ 65 Find the given module 'name' in the search path, returning None where no 66 such module could be found, or a 2-tuple from the 'find' method 67 otherwise. 68 """ 69 70 for d in self.path: 71 m = self.find(d, name) 72 if m: return m 73 return None 74 75 def find(self, d, name): 76 77 """ 78 In the directory 'd', find the given module 'name', where 'name' can 79 either refer to a single file module or to a package. Return None if the 80 'name' cannot be associated with either a file or a package directory, 81 or a 2-tuple from '_find_package' or '_find_module' otherwise. 82 """ 83 84 m = self._find_package(d, name) 85 if m: return m 86 m = self._find_module(d, name) 87 if m: return m 88 return None 89 90 def _find_module(self, d, name): 91 92 """ 93 In the directory 'd', find the given module 'name', returning None where 94 no suitable file exists in the directory, or a 2-tuple consisting of 95 None (indicating that no package directory is involved) and a filename 96 indicating the location of the module. 97 """ 98 99 name_py = name + os.extsep + "py" 100 filename = self._find_file(d, name_py) 101 if filename: 102 return None, filename 103 return None 104 105 def _find_package(self, d, name): 106 107 """ 108 In the directory 'd', find the given package 'name', returning None 109 where no suitable package directory exists, or a 2-tuple consisting of 110 a directory (indicating the location of the package directory itself) 111 and a filename indicating the location of the __init__.py module which 112 declares the package's top-level contents. 113 """ 114 115 filename = self._find_file(d, name) 116 if filename: 117 init_py = "__init__" + os.path.extsep + "py" 118 init_py_filename = self._find_file(filename, init_py) 119 if init_py_filename: 120 return filename, init_py_filename 121 return None 122 123 def _find_file(self, d, filename): 124 125 """ 126 Return the filename obtained when searching the directory 'd' for the 127 given 'filename', or None if no actual file exists for the filename. 128 """ 129 130 filename = os.path.join(d, filename) 131 if os.path.exists(filename): 132 return filename 133 else: 134 return None 135 136 def load(self, name, builtins=None, alias=None): 137 138 """ 139 Load the module or package with the given 'name' and using the specified 140 'builtins'. Return an Attribute object referencing the loaded module or 141 package, or None if no such module or package exists. 142 """ 143 144 if self.modules.has_key(name): 145 return Attribute(None, self.modules[name]) 146 147 # Split the name into path components, and try to find the uppermost in 148 # the search path. 149 150 path = name.split(".") 151 m = self.find_in_path(path[0]) 152 if not m: 153 return None # NOTE: Import error. 154 d, filename = m 155 156 # Either acquire a reference to an already-imported module, or load the 157 # module from a file. 158 159 if self.modules.has_key(path[0]): 160 top = module = self.modules[path[0]] 161 else: 162 top = module = self.load_from_file(filename, builtins, path[0]) 163 164 # For hierarchical names, traverse each path component... 165 166 if len(path) > 1: 167 path_so_far = path[:1] 168 for p in path[1:]: 169 path_so_far.append(p) 170 171 # Find the package or module concerned. 172 173 m = self.find(d, p) 174 if not m: 175 return None # NOTE: Import error. 176 d, filename = m 177 module_name = ".".join(path_so_far) 178 179 # Either reference an imported module or load one from a file. 180 181 if self.modules.has_key(module_name): 182 submodule = self.modules[module_name] 183 else: 184 submodule = self.load_from_file(filename, builtins, module_name) 185 186 # Store the submodule within its parent module. 187 188 module.namespace[p] = [Attribute(None, submodule)] 189 module = submodule 190 191 # Return either the deepest or the uppermost module. 192 193 if alias: 194 return Attribute(None, module) 195 else: 196 return Attribute(None, top) 197 198 def load_from_file(self, name, builtins=None, module_name=None): 199 200 """ 201 Load the module with the given 'name' (which may be a full module path), 202 using the optional 'builtins' to resolve built-in names. 203 """ 204 205 if module_name is None: 206 if builtins is None: 207 module_name = "__builtins__" 208 else: 209 module_name = "__main__" 210 211 # Simplify, fix names, and annotate the module. 212 213 module = simplify.ast.simplify(name, builtins is None, module_name) 214 simplify.fixnames.fix(module, builtins) 215 if self.annotate: 216 simplify.annotate.annotate(module, builtins, self) 217 218 # Record the module. 219 220 self.modules[module_name] = module 221 return module 222 223 def fix_instances(self): 224 225 "Fix instances for all modules loaded by this importer." 226 227 for module in self.get_modules(): 228 simplify.fixinstances.fix_structures(module) 229 for module in self.get_modules(): 230 simplify.fixinstances.fix(module) 231 232 # vim: tabstop=4 expandtab shiftwidth=4