mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	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:
		
							parent
							
								
									5c26e86096
								
							
						
					
					
						commit
						0eb32a65b0
					
				
					 3 changed files with 101 additions and 0 deletions
				
			
		
							
								
								
									
										49
									
								
								Doc/dist/dist.tex
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								Doc/dist/dist.tex
									
										
									
									
										vendored
									
									
								
							|  | @ -652,6 +652,55 @@ setup(... | ||||||
| \end{verbatim} | \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} | \subsection{Installing Additional Files} | ||||||
| 
 | 
 | ||||||
| The \option{data\_files} option can be used to specify additional | The \option{data\_files} option can be used to specify additional | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ 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 | ||||||
|  |         self.package_data = None | ||||||
|         self.package_dir = None |         self.package_dir = None | ||||||
|         self.compile = 0 |         self.compile = 0 | ||||||
|         self.optimize = 0 |         self.optimize = 0 | ||||||
|  | @ -51,6 +52,8 @@ def finalize_options (self): | ||||||
|         # options -- list of packages and list of modules. |         # options -- list of packages and list of modules. | ||||||
|         self.packages = self.distribution.packages |         self.packages = self.distribution.packages | ||||||
|         self.py_modules = self.distribution.py_modules |         self.py_modules = self.distribution.py_modules | ||||||
|  |         self.package_data = self.distribution.package_data | ||||||
|  |         self.data_files = self.get_data_files() | ||||||
|         self.package_dir = {} |         self.package_dir = {} | ||||||
|         if self.distribution.package_dir: |         if self.distribution.package_dir: | ||||||
|             for name, path in self.distribution.package_dir.items(): |             for name, path in self.distribution.package_dir.items(): | ||||||
|  | @ -92,11 +95,53 @@ def run (self): | ||||||
|             self.build_modules() |             self.build_modules() | ||||||
|         if self.packages: |         if self.packages: | ||||||
|             self.build_packages() |             self.build_packages() | ||||||
|  |             self.build_package_data() | ||||||
| 
 | 
 | ||||||
|         self.byte_compile(self.get_outputs(include_bytecode=0)) |         self.byte_compile(self.get_outputs(include_bytecode=0)) | ||||||
| 
 | 
 | ||||||
|     # run () |     # 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): |     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 | ||||||
|  | @ -304,6 +349,12 @@ def get_outputs (self, include_bytecode=1): | ||||||
|                 if self.optimize > 0: |                 if self.optimize > 0: | ||||||
|                     outputs.append(filename + "o") |                     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 |         return outputs | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -158,6 +158,7 @@ def __init__ (self, attrs=None): | ||||||
|         # than of the Distribution itself.  We provide aliases for them in |         # than of the Distribution itself.  We provide aliases for them in | ||||||
|         # Distribution as a convenience to the developer. |         # Distribution as a convenience to the developer. | ||||||
|         self.packages = None |         self.packages = None | ||||||
|  |         self.package_data = {} | ||||||
|         self.package_dir = None |         self.package_dir = None | ||||||
|         self.py_modules = None |         self.py_modules = None | ||||||
|         self.libraries = None |         self.libraries = None | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Fred Drake
						Fred Drake