cleaned up distutils.command.build_py

This commit is contained in:
Tarek Ziadé 2009-07-03 09:01:07 +00:00
parent 65ec61ed06
commit fe97ebbf62

View file

@ -4,16 +4,15 @@
__revision__ = "$Id$" __revision__ = "$Id$"
import string, os import os
from types import *
from glob import glob from glob import glob
from distutils.core import Command from distutils.core import Command
from distutils.errors import * from distutils.errors import DistutilsOptionError, DistutilsFileError
from distutils.util import convert_path from distutils.util import convert_path
from distutils import log from distutils import log
class build_py (Command): class build_py(Command):
description = "\"build\" pure Python modules (copy to build directory)" description = "\"build\" pure Python modules (copy to build directory)"
@ -30,8 +29,7 @@ class build_py (Command):
boolean_options = ['compile', 'force'] boolean_options = ['compile', 'force']
negative_opt = {'no-compile' : 'compile'} negative_opt = {'no-compile' : 'compile'}
def initialize_options(self):
def initialize_options (self):
self.build_lib = None self.build_lib = None
self.py_modules = None self.py_modules = None
self.package = None self.package = None
@ -41,7 +39,7 @@ def initialize_options (self):
self.optimize = 0 self.optimize = 0
self.force = None self.force = None
def finalize_options (self): def finalize_options(self):
self.set_undefined_options('build', self.set_undefined_options('build',
('build_lib', 'build_lib'), ('build_lib', 'build_lib'),
('force', 'force')) ('force', 'force'))
@ -59,15 +57,14 @@ def finalize_options (self):
# Ick, copied straight from install_lib.py (fancy_getopt needs a # Ick, copied straight from install_lib.py (fancy_getopt needs a
# type system! Hell, *everything* needs a type system!!!) # type system! Hell, *everything* needs a type system!!!)
if type(self.optimize) is not IntType: if not isinstance(self.optimize, int):
try: try:
self.optimize = int(self.optimize) self.optimize = int(self.optimize)
assert 0 <= self.optimize <= 2 assert 0 <= self.optimize <= 2
except (ValueError, AssertionError): except (ValueError, AssertionError):
raise DistutilsOptionError, "optimize must be 0, 1, or 2" raise DistutilsOptionError("optimize must be 0, 1, or 2")
def run (self):
def run(self):
# XXX copy_file by default preserves atime and mtime. IMHO this is # XXX copy_file by default preserves atime and mtime. IMHO this is
# the right thing to do, but perhaps it should be an option -- in # the right thing to do, but perhaps it should be an option -- in
# particular, a site administrator might want installed files to # particular, a site administrator might want installed files to
@ -97,9 +94,7 @@ def run (self):
self.byte_compile(self.get_outputs(include_bytecode=0)) self.byte_compile(self.get_outputs(include_bytecode=0))
# run () def get_data_files(self):
def get_data_files (self):
"""Generate list of '(package,src_dir,build_dir,filenames)' tuples""" """Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
data = [] data = []
if not self.packages: if not self.packages:
@ -123,7 +118,7 @@ def get_data_files (self):
data.append((package, src_dir, build_dir, filenames)) data.append((package, src_dir, build_dir, filenames))
return data return data
def find_data_files (self, package, src_dir): def find_data_files(self, package, src_dir):
"""Return filenames for package's data files in 'src_dir'""" """Return filenames for package's data files in 'src_dir'"""
globs = (self.package_data.get('', []) globs = (self.package_data.get('', [])
+ self.package_data.get(package, [])) + self.package_data.get(package, []))
@ -135,7 +130,7 @@ def find_data_files (self, package, src_dir):
files.extend([fn for fn in filelist if fn not in files]) files.extend([fn for fn in filelist if fn not in files])
return files return files
def build_package_data (self): def build_package_data(self):
"""Copy data files into build directory""" """Copy data files into build directory"""
lastdir = None lastdir = None
for package, src_dir, build_dir, filenames in self.data_files: for package, src_dir, build_dir, filenames in self.data_files:
@ -145,23 +140,23 @@ def build_package_data (self):
self.copy_file(os.path.join(src_dir, filename), target, self.copy_file(os.path.join(src_dir, filename), target,
preserve_mode=False) preserve_mode=False)
def get_package_dir (self, package): def get_package_dir(self, package):
"""Return the directory, relative to the top of the source """Return the directory, relative to the top of the source
distribution, where package 'package' should be found distribution, where package 'package' should be found
(at least according to the 'package_dir' option, if any).""" (at least according to the 'package_dir' option, if any)."""
path = string.split(package, '.') path = package.split('.')
if not self.package_dir: if not self.package_dir:
if path: if path:
return apply(os.path.join, path) return os.path.join(*path)
else: else:
return '' return ''
else: else:
tail = [] tail = []
while path: while path:
try: try:
pdir = self.package_dir[string.join(path, '.')] pdir = self.package_dir['.'.join(path)]
except KeyError: except KeyError:
tail.insert(0, path[-1]) tail.insert(0, path[-1])
del path[-1] del path[-1]
@ -181,27 +176,23 @@ def get_package_dir (self, package):
tail.insert(0, pdir) tail.insert(0, pdir)
if tail: if tail:
return apply(os.path.join, tail) return os.path.join(*tail)
else: else:
return '' return ''
# get_package_dir () def check_package(self, package, package_dir):
def check_package (self, package, package_dir):
# Empty dir name means current directory, which we can probably # Empty dir name means current directory, which we can probably
# assume exists. Also, os.path.exists and isdir don't know about # assume exists. Also, os.path.exists and isdir don't know about
# my "empty string means current dir" convention, so we have to # my "empty string means current dir" convention, so we have to
# circumvent them. # circumvent them.
if package_dir != "": if package_dir != "":
if not os.path.exists(package_dir): if not os.path.exists(package_dir):
raise DistutilsFileError, \ raise DistutilsFileError(
"package directory '%s' does not exist" % package_dir "package directory '%s' does not exist" % package_dir)
if not os.path.isdir(package_dir): if not os.path.isdir(package_dir):
raise DistutilsFileError, \ raise DistutilsFileError(
("supposed package directory '%s' exists, " + "supposed package directory '%s' exists, "
"but is not a directory") % package_dir "but is not a directory" % package_dir)
# Require __init__.py for all but the "root package" # Require __init__.py for all but the "root package"
if package: if package:
@ -216,20 +207,14 @@ def check_package (self, package, package_dir):
# __init__.py doesn't exist -- so don't return the filename. # __init__.py doesn't exist -- so don't return the filename.
return None return None
# check_package () def check_module(self, module, module_file):
def check_module (self, module, module_file):
if not os.path.isfile(module_file): if not os.path.isfile(module_file):
log.warn("file %s (for module %s) not found", module_file, module) log.warn("file %s (for module %s) not found", module_file, module)
return 0 return False
else: else:
return 1 return True
# check_module () def find_package_modules(self, package, package_dir):
def find_package_modules (self, package, package_dir):
self.check_package(package, package_dir) self.check_package(package, package_dir)
module_files = glob(os.path.join(package_dir, "*.py")) module_files = glob(os.path.join(package_dir, "*.py"))
modules = [] modules = []
@ -244,8 +229,7 @@ def find_package_modules (self, package, package_dir):
self.debug_print("excluding %s" % setup_script) self.debug_print("excluding %s" % setup_script)
return modules return modules
def find_modules(self):
def find_modules (self):
"""Finds individually-specified Python modules, ie. those listed by """Finds individually-specified Python modules, ie. those listed by
module name in 'self.py_modules'. Returns a list of tuples (package, module name in 'self.py_modules'. Returns a list of tuples (package,
module_base, filename): 'package' is a tuple of the path through module_base, filename): 'package' is a tuple of the path through
@ -254,7 +238,6 @@ def find_modules (self):
".py" file (relative to the distribution root) that implements the ".py" file (relative to the distribution root) that implements the
module. module.
""" """
# Map package names to tuples of useful info about the package: # Map package names to tuples of useful info about the package:
# (package_dir, checked) # (package_dir, checked)
# package_dir - the directory where we'll find source files for # package_dir - the directory where we'll find source files for
@ -270,10 +253,9 @@ def find_modules (self):
# just the "package" for a toplevel is empty (either an empty # just the "package" for a toplevel is empty (either an empty
# string or empty list, depending on context). Differences: # string or empty list, depending on context). Differences:
# - don't check for __init__.py in directory for empty package # - don't check for __init__.py in directory for empty package
for module in self.py_modules: for module in self.py_modules:
path = string.split(module, '.') path = module.split('.')
package = string.join(path[0:-1], '.') package = '.'.join(path[0:-1])
module_base = path[-1] module_base = path[-1]
try: try:
@ -299,16 +281,12 @@ def find_modules (self):
return modules return modules
# find_modules () def find_all_modules(self):
def find_all_modules (self):
"""Compute the list of all modules that will be built, whether """Compute the list of all modules that will be built, whether
they are specified one-module-at-a-time ('self.py_modules') or they are specified one-module-at-a-time ('self.py_modules') or
by whole packages ('self.packages'). Return a list of tuples by whole packages ('self.packages'). Return a list of tuples
(package, module, module_file), just like 'find_modules()' and (package, module, module_file), just like 'find_modules()' and
'find_package_modules()' do.""" 'find_package_modules()' do."""
modules = [] modules = []
if self.py_modules: if self.py_modules:
modules.extend(self.find_modules()) modules.extend(self.find_modules())
@ -317,32 +295,20 @@ def find_all_modules (self):
package_dir = self.get_package_dir(package) package_dir = self.get_package_dir(package)
m = self.find_package_modules(package, package_dir) m = self.find_package_modules(package, package_dir)
modules.extend(m) modules.extend(m)
return modules return modules
# find_all_modules () def get_source_files(self):
return [module[-1] for module in self.find_all_modules()]
def get_module_outfile(self, build_dir, package, module):
def get_source_files (self):
modules = self.find_all_modules()
filenames = []
for module in modules:
filenames.append(module[-1])
return filenames
def get_module_outfile (self, build_dir, package, module):
outfile_path = [build_dir] + list(package) + [module + ".py"] outfile_path = [build_dir] + list(package) + [module + ".py"]
return os.path.join(*outfile_path) return os.path.join(*outfile_path)
def get_outputs(self, include_bytecode=1):
def get_outputs (self, include_bytecode=1):
modules = self.find_all_modules() modules = self.find_all_modules()
outputs = [] outputs = []
for (package, module, module_file) in modules: for (package, module, module_file) in modules:
package = string.split(package, '.') package = package.split('.')
filename = self.get_module_outfile(self.build_lib, package, module) filename = self.get_module_outfile(self.build_lib, package, module)
outputs.append(filename) outputs.append(filename)
if include_bytecode: if include_bytecode:
@ -359,13 +325,12 @@ def get_outputs (self, include_bytecode=1):
return outputs return outputs
def build_module(self, module, module_file, package):
def build_module (self, module, module_file, package): if isinstance(package, str):
if type(package) is StringType: package = package.split('.')
package = string.split(package, '.') elif not isinstance(package, (list, tuple)):
elif type(package) not in (ListType, TupleType): raise TypeError(
raise TypeError, \ "'package' must be a string (dot-separated), list, or tuple")
"'package' must be a string (dot-separated), list, or tuple"
# Now put the module source file into the "build" area -- this is # Now put the module source file into the "build" area -- this is
# easy, we just copy it somewhere under self.build_lib (the build # easy, we just copy it somewhere under self.build_lib (the build
@ -375,9 +340,7 @@ def build_module (self, module, module_file, package):
self.mkpath(dir) self.mkpath(dir)
return self.copy_file(module_file, outfile, preserve_mode=0) return self.copy_file(module_file, outfile, preserve_mode=0)
def build_modules(self):
def build_modules (self):
modules = self.find_modules() modules = self.find_modules()
for (package, module, module_file) in modules: for (package, module, module_file) in modules:
@ -387,11 +350,7 @@ def build_modules (self):
# under self.build_lib.) # under self.build_lib.)
self.build_module(module, module_file, package) self.build_module(module, module_file, package)
# build_modules () def build_packages(self):
def build_packages (self):
for package in self.packages: for package in self.packages:
# Get list of (package, module, module_file) tuples based on # Get list of (package, module, module_file) tuples based on
@ -412,10 +371,7 @@ def build_packages (self):
assert package == package_ assert package == package_
self.build_module(module, module_file, package) self.build_module(module, module_file, package)
# build_packages () def byte_compile(self, files):
def byte_compile (self, files):
from distutils.util import byte_compile from distutils.util import byte_compile
prefix = self.build_lib prefix = self.build_lib
if prefix[-1] != os.sep: if prefix[-1] != os.sep:
@ -431,5 +387,3 @@ def byte_compile (self, files):
if self.optimize > 0: if self.optimize > 0:
byte_compile(files, optimize=self.optimize, byte_compile(files, optimize=self.optimize,
force=self.force, prefix=prefix, dry_run=self.dry_run) force=self.force, prefix=prefix, dry_run=self.dry_run)
# class build_py