Add support for package data.

This is basically the support for package data from Phillip Eby's
setuptools package.  I've changed it only to fit it into the core
implementation rather than to live in subclasses, and added
documentation.
This commit is contained in:
Fred Drake 2004-06-11 21:50:33 +00:00
parent 5c26e86096
commit 0eb32a65b0
3 changed files with 101 additions and 0 deletions

49
Doc/dist/dist.tex vendored
View file

@ -652,6 +652,55 @@ setup(...
\end{verbatim}
\subsection{Installing Package Data}
Often, additional files need to be installed into a package. These
files are often data that's closely related to the package's
implementation, or text files containing documentation that might be
of interest to programmers using the package. These files are called
\dfn{package data}.
Package data can be added to packages using the \code{package_data}
keyword argument to the \function{setup()} function. The value must
be a mapping from package name to a list of relative path names that
should be copied into the package. The paths are interpreted as
relative to the directory containing the package (information from the
\code{package_dir} mapping is used if appropriate); that is, the files
are expected to be part of the package in the source directories.
They may contain glob patterns as well.
The path names may contain directory portions; any necessary
directories will be created in the installation.
For example, if a package should contain a subdirectory with several
data files, the files can be arranged like this in the source tree:
\begin{verbatim}
setup.py
src/
mypkg/
__init__.py
module.py
data/
tables.dat
spoons.dat
forks.dat
\end{verbatim}
The corresponding call to \function{setup()} might be:
\begin{verbatim}
setup(...,
packages=['mypkg'],
package_dir={'mypkg': 'src/mypkg'},
package_data={'pypkg': ['data/*.dat']},
)
\end{verbatim}
\versionadded{2.4}
\subsection{Installing Additional Files}
The \option{data\_files} option can be used to specify additional

View file

@ -37,6 +37,7 @@ def initialize_options (self):
self.build_lib = None
self.py_modules = None
self.package = None
self.package_data = None
self.package_dir = None
self.compile = 0
self.optimize = 0
@ -51,6 +52,8 @@ def finalize_options (self):
# options -- list of packages and list of modules.
self.packages = self.distribution.packages
self.py_modules = self.distribution.py_modules
self.package_data = self.distribution.package_data
self.data_files = self.get_data_files()
self.package_dir = {}
if self.distribution.package_dir:
for name, path in self.distribution.package_dir.items():
@ -92,11 +95,53 @@ def run (self):
self.build_modules()
if self.packages:
self.build_packages()
self.build_package_data()
self.byte_compile(self.get_outputs(include_bytecode=0))
# run ()
def get_data_files (self):
"""Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
data = []
for package in self.packages:
# Locate package source directory
src_dir = self.get_package_dir(package)
# Compute package build directory
build_dir = os.path.join(*([self.build_lib] + package.split('.')))
# Length of path to strip from found files
plen = len(src_dir)+1
# Strip directory from globbed filenames
filenames = [
file[plen:] for file in self.find_data_files(package, src_dir)
]
data.append((package, src_dir, build_dir, filenames))
return data
def find_data_files (self, package, src_dir):
"""Return filenames for package's data files in 'src_dir'"""
globs = (self.package_data.get('', [])
+ self.package_data.get(package, []))
files = []
for pattern in globs:
# Each pattern has to be converted to a platform-specific path
filelist = glob(os.path.join(src_dir, convert_path(pattern)))
# Files that match more than one pattern are only added once
files.extend([fn for fn in filelist if fn not in files])
return files
def build_package_data (self):
"""Copy data files into build directory"""
lastdir = None
for package, src_dir, build_dir, filenames in self.data_files:
for filename in filenames:
target = os.path.join(build_dir, filename)
self.mkpath(os.path.dirname(target))
self.copy_file(os.path.join(src_dir, filename), target,
preserve_mode=False)
def get_package_dir (self, package):
"""Return the directory, relative to the top of the source
@ -304,6 +349,12 @@ def get_outputs (self, include_bytecode=1):
if self.optimize > 0:
outputs.append(filename + "o")
outputs += [
os.path.join(build_dir, filename)
for package, src_dir, build_dir, filenames in self.data_files
for filename in filenames
]
return outputs

View file

@ -158,6 +158,7 @@ def __init__ (self, attrs=None):
# than of the Distribution itself. We provide aliases for them in
# Distribution as a convenience to the developer.
self.packages = None
self.package_data = {}
self.package_dir = None
self.py_modules = None
self.libraries = None