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 method used. 26 Here, the standard path for module searching is used: 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 return self.modules.values() 60 61 def find_in_path(self, name): 62 63 """ 64 Find the given module 'name' in the search path, returning None where no 65 such module could be found, or a 2-tuple from the 'find' method 66 otherwise. 67 """ 68 69 for d in self.path: 70 m = self.find(d, name) 71 if m: return m 72 return None 73 74 def find(self, d, name): 75 76 """ 77 In the directory 'd', find the given module 'name', where 'name' can 78 either refer to a single file module or to a package. Return None if the 79 'name' cannot be associated with either a file or a package directory, 80 or a 2-tuple from '_find_package' or '_find_module' otherwise. 81 """ 82 83 m = self._find_package(d, name) 84 if m: return m 85 m = self._find_module(d, name) 86 if m: return m 87 return None 88 89 def _find_module(self, d, name): 90 91 """ 92 In the directory 'd', find the given module 'name', returning None where 93 no suitable file exists in the directory, or a 2-tuple consisting of 94 None (indicating that no package directory is involved) and a filename 95 indicating the location of the module. 96 """ 97 98 name_py = name + os.extsep + "py" 99 filename = self._find_file(d, name_py) 100 if filename: 101 return None, filename 102 return None 103 104 def _find_package(self, d, name): 105 106 """ 107 In the directory 'd', find the given package 'name', returning None 108 where no suitable package directory exists, or a 2-tuple consisting of 109 a directory (indicating the location of the package directory itself) 110 and a filename indicating the location of the __init__.py module which 111 declares the package's top-level contents. 112 """ 113 114 filename = self._find_file(d, name) 115 if filename: 116 init_py = "__init__" + os.path.extsep + "py" 117 init_py_filename = self._find_file(filename, init_py) 118 if init_py_filename: 119 return filename, init_py_filename 120 return None 121 122 def _find_file(self, d, filename): 123 124 """ 125 Return the filename obtained when searching the directory 'd' for the 126 given 'filename', or None if no actual file exists for the filename. 127 """ 128 129 filename = os.path.join(d, filename) 130 if os.path.exists(filename): 131 return filename 132 else: 133 return None 134 135 def load(self, name, builtins=None, alias=None): 136 137 """ 138 Load the module or package with the given 'name' and using the specified 139 'builtins'. Return an Attribute object referencing the loaded module or 140 package, or None if no such module or package exists. 141 """ 142 143 if self.modules.has_key(name): 144 return Attribute(None, self.modules[name]) 145 146 path = name.split(".") 147 m = self.find_in_path(path[0]) 148 if not m: 149 return None # NOTE: Import error. 150 d, filename = m 151 152 if self.modules.has_key(path[0]): 153 top = module = self.modules[path[0]] 154 else: 155 top = module = self.load_from_file(filename, builtins, path[0]) 156 157 if len(path) > 1: 158 path_so_far = path[:1] 159 for p in path[1:]: 160 path_so_far.append(p) 161 m = self.find(d, p) 162 if not m: 163 return None # NOTE: Import error. 164 d, filename = m 165 module_name = ".".join(path_so_far) 166 167 if self.modules.has_key(module_name): 168 submodule = self.modules[module_name] 169 else: 170 submodule = self.load_from_file(filename, builtins, module_name) 171 172 # Store the submodule within its parent module. 173 174 module.namespace[p] = [Attribute(None, submodule)] 175 module = submodule 176 177 if alias: 178 return Attribute(None, module) 179 else: 180 return Attribute(None, top) 181 182 def load_from_file(self, name, builtins=None, module_name=None): 183 184 """ 185 Load the module with the given 'name' (which may be a full module path), 186 using the optional 'builtins' to resolve built-in names. 187 """ 188 189 if module_name is None: 190 if builtins is None: 191 module_name = "__builtins__" 192 else: 193 module_name = "__main__" 194 195 module = simplify.ast.simplify(name, builtins is None, module_name) 196 simplify.fixnames.fix(module, builtins) 197 if self.annotate: 198 simplify.annotate.annotate(module, builtins, self) 199 200 # Record the module. 201 202 self.modules[module_name] = module 203 return module 204 205 def fix_instances(self): 206 207 "Fix instances for all modules loaded by this importer." 208 209 for module in self.get_modules(): 210 simplify.fixinstances.fix_structures(module) 211 for module in self.get_modules(): 212 simplify.fixinstances.fix(module) 213 214 # vim: tabstop=4 expandtab shiftwidth=4