[Distutils] Installing (data-)files in package directories

Thomas Heller theller at python.net
Wed Nov 19 15:06:41 EST 2003


It seems installing data-files in package directories is a common
requirement - at least for me.

Readme files, data files needed by the packages - the bdist_wininst.exe
file is such an example.  It needs to be in the same directory as the
distutils.command.bdist_wininst module.

So here is a build_py subclass (contained in a setup script) which does
this. Any comments?

Thomas

-------------- next part --------------
import sys
if len(sys.argv) == 1:
    sys.argv.append("install")

################

from distutils.core import setup

################

from distutils.command import build_py
import glob, os

class my_build_py(build_py.build_py):
    """This build_py replacement not only builds Python packages and
    modules, it also builds (copies) all other files in the packages
    into the build tree."""

    # This does the right thing with the 'install' command as well as
    # the bdist_wininst command - eventually install all these files
    # into the final destination directories.

    # A possible improvement would be to be be able to specify which
    # files are installed, but, as I see it, this would require
    # changes to distutils' distribution class as well - how could the
    # filenames or wildcards be specified otherwise?

    def run(self):
        build_py.build_py.run(self)

        for package in self.packages:
            package_dir = self.get_package_dir(package)
            files = self.find_package_files(package, package_dir)
            for (dest_base, package_, file_path) in files:
                assert package == package_
                self.build_file(dest_base, package, file_path)

    def find_package_files(self, package, package_dir):
        # return a list of triples, the first item is the basename
        # of the destination file, the second is the package name,
        # and the third item is the source filename
        result = []
        for fname in glob.glob(os.path.join(package_dir, "*.*")):
            base, ext = os.path.splitext(fname)
            if ext in (".py", ".pyc", ".pyo"):
                continue
            result.append((os.path.basename(fname), package, fname))
        return result

    def build_file(self, dest_base, package, file_path):
        from types import StringType, ListType, TupleType
        if type(package) is StringType:
            package = package.split('.')
        elif type(package) not in (ListType, TupleType):
            raise TypeError, \
                  "'package' must be a string (dot-separated), list, or tuple"
        parts = [self.build_lib] + list(package) + [dest_base]
        outfile = os.path.join(*parts)
        dir = os.path.dirname(outfile)
        self.mkpath(dir)
        return self.copy_file(file_path, outfile, preserve_mode=0)

################

setup(name="test",
      packages = ["my_package"],
      cmdclass = {"build_py": my_build_py},
      )


More information about the Distutils-SIG mailing list