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