1.1 --- a/simplify/__init__.py Sat Jun 23 01:57:13 2007 +0200
1.2 +++ b/simplify/__init__.py Sat Jun 23 21:10:01 2007 +0200
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 The simplify package for processing Python source code.
1.6
1.7 -Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This software is free software; you can redistribute it and/or
1.11 modify it under the terms of the GNU General Public License as
1.12 @@ -19,6 +19,196 @@
1.13 License along with this library; see the file LICENCE.txt
1.14 If not, write to the Free Software Foundation, Inc.,
1.15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
1.16 +
1.17 +--------
1.18 +
1.19 +To use this module, an importer should be constructed and the load method used.
1.20 +Here, the standard path for module searching is used:
1.21 +
1.22 +importer = Importer(sys.path)
1.23 +importer.load_from_file(builtins)
1.24 +importer.load_from_file(filename, builtins)
1.25 """
1.26
1.27 +from simplify.simplified import *
1.28 +import simplify.ast
1.29 +import simplify.fixnames
1.30 +import simplify.annotate
1.31 +import simplify.fixinstances
1.32 +
1.33 +class Importer:
1.34 +
1.35 + "An import machine, searching for and loading modules."
1.36 +
1.37 + def __init__(self, path=None, annotate=1, fixinstances=1):
1.38 +
1.39 + """
1.40 + Initialise the importer with the given search 'path' - a list of
1.41 + directories to search for Python modules. If the optional 'annotate'
1.42 + parameter is set to a false value (unlike the default), no annotation
1.43 + will be performed.
1.44 + false value (unlike the default), no instance fixing will be performed.
1.45 + """
1.46 +
1.47 + self.path = path or [os.getcwd()]
1.48 + self.path.append(libdir)
1.49 + self.annotate = annotate
1.50 + self.modules = {}
1.51 +
1.52 + def get_modules(self):
1.53 + return self.modules.values()
1.54 +
1.55 + def find_in_path(self, name):
1.56 +
1.57 + """
1.58 + Find the given module 'name' in the search path, returning None where no
1.59 + such module could be found, or a 2-tuple from the 'find' method
1.60 + otherwise.
1.61 + """
1.62 +
1.63 + for d in self.path:
1.64 + m = self.find(d, name)
1.65 + if m: return m
1.66 + return None
1.67 +
1.68 + def find(self, d, name):
1.69 +
1.70 + """
1.71 + In the directory 'd', find the given module 'name', where 'name' can
1.72 + either refer to a single file module or to a package. Return None if the
1.73 + 'name' cannot be associated with either a file or a package directory,
1.74 + or a 2-tuple from '_find_package' or '_find_module' otherwise.
1.75 + """
1.76 +
1.77 + m = self._find_package(d, name)
1.78 + if m: return m
1.79 + m = self._find_module(d, name)
1.80 + if m: return m
1.81 + return None
1.82 +
1.83 + def _find_module(self, d, name):
1.84 +
1.85 + """
1.86 + In the directory 'd', find the given module 'name', returning None where
1.87 + no suitable file exists in the directory, or a 2-tuple consisting of
1.88 + None (indicating that no package directory is involved) and a filename
1.89 + indicating the location of the module.
1.90 + """
1.91 +
1.92 + name_py = name + os.extsep + "py"
1.93 + filename = self._find_file(d, name_py)
1.94 + if filename:
1.95 + return None, filename
1.96 + return None
1.97 +
1.98 + def _find_package(self, d, name):
1.99 +
1.100 + """
1.101 + In the directory 'd', find the given package 'name', returning None
1.102 + where no suitable package directory exists, or a 2-tuple consisting of
1.103 + a directory (indicating the location of the package directory itself)
1.104 + and a filename indicating the location of the __init__.py module which
1.105 + declares the package's top-level contents.
1.106 + """
1.107 +
1.108 + filename = self._find_file(d, name)
1.109 + if filename:
1.110 + init_py = "__init__" + os.path.extsep + "py"
1.111 + init_py_filename = self._find_file(filename, init_py)
1.112 + if init_py_filename:
1.113 + return filename, init_py_filename
1.114 + return None
1.115 +
1.116 + def _find_file(self, d, filename):
1.117 +
1.118 + """
1.119 + Return the filename obtained when searching the directory 'd' for the
1.120 + given 'filename', or None if no actual file exists for the filename.
1.121 + """
1.122 +
1.123 + filename = os.path.join(d, filename)
1.124 + if os.path.exists(filename):
1.125 + return filename
1.126 + else:
1.127 + return None
1.128 +
1.129 + def load(self, name, builtins=None, alias=None):
1.130 +
1.131 + """
1.132 + Load the module or package with the given 'name' and using the specified
1.133 + 'builtins'. Return an Attribute object referencing the loaded module or
1.134 + package, or None if no such module or package exists.
1.135 + """
1.136 +
1.137 + if self.modules.has_key(name):
1.138 + return Attribute(None, self.modules[name])
1.139 +
1.140 + path = name.split(".")
1.141 + m = self.find_in_path(path[0])
1.142 + if not m:
1.143 + return None # NOTE: Import error.
1.144 + d, filename = m
1.145 +
1.146 + if self.modules.has_key(path[0]):
1.147 + top = module = self.modules[path[0]]
1.148 + else:
1.149 + top = module = self.load_from_file(filename, builtins, path[0])
1.150 +
1.151 + if len(path) > 1:
1.152 + path_so_far = path[:1]
1.153 + for p in path[1:]:
1.154 + path_so_far.append(p)
1.155 + m = self.find(d, p)
1.156 + if not m:
1.157 + return None # NOTE: Import error.
1.158 + d, filename = m
1.159 + module_name = ".".join(path_so_far)
1.160 +
1.161 + if self.modules.has_key(module_name):
1.162 + submodule = self.modules[module_name]
1.163 + else:
1.164 + submodule = self.load_from_file(filename, builtins, module_name)
1.165 +
1.166 + # Store the submodule within its parent module.
1.167 +
1.168 + module.namespace[p] = [Attribute(None, submodule)]
1.169 + module = submodule
1.170 +
1.171 + if alias:
1.172 + return Attribute(None, module)
1.173 + else:
1.174 + return Attribute(None, top)
1.175 +
1.176 + def load_from_file(self, name, builtins=None, module_name=None):
1.177 +
1.178 + """
1.179 + Load the module with the given 'name' (which may be a full module path),
1.180 + using the optional 'builtins' to resolve built-in names.
1.181 + """
1.182 +
1.183 + if module_name is None:
1.184 + if builtins is None:
1.185 + module_name = "__builtins__"
1.186 + else:
1.187 + module_name = "__main__"
1.188 +
1.189 + module = simplify.ast.simplify(name, builtins is None, module_name)
1.190 + simplify.fixnames.fix(module, builtins)
1.191 + if self.annotate:
1.192 + simplify.annotate.annotate(module, builtins, self)
1.193 +
1.194 + # Record the module.
1.195 +
1.196 + self.modules[module_name] = module
1.197 + return module
1.198 +
1.199 + def fix_instances(self):
1.200 +
1.201 + "Fix instances for all modules loaded by this importer."
1.202 +
1.203 + for module in self.get_modules():
1.204 + simplify.fixinstances.fix_structures(module)
1.205 + for module in self.get_modules():
1.206 + simplify.fixinstances.fix(module)
1.207 +
1.208 # vim: tabstop=4 expandtab shiftwidth=4