Make setup.py work with all versions of Distutils
Hello developers, some of you may have noticed that the Distutils allow customized command classes by inheriting them. This is extremely powerful especially when it comes to compatibility fixes. I'll summarize all of my custom functions which will work around a number of unknown/known/fixed bugs in the Distutils. If you want to be compatible with older versions of the Distutils, you can include them in your setup.py file. 1) Distutils traceback when DISTUTILS_DEBUG is set. This is a known but unfixed bug. Just override the dump_dirs function in install.py with your own: from distutils.core import DEBUG import string class MyInstall(install): def dump_dirs (self, msg): if DEBUG: from distutils.fancy_getopt import longopt_xlate print msg + ":" for opt in self.user_options: opt_name = opt[0] if opt_name[-1] == "=": opt_name = opt_name[0:-1] if self.negative_opt.has_key(opt_name): opt_name = string.translate(self.negative_opt[opt_name], longopt_xlate) val = not getattr(self, opt_name) else: opt_name = string.translate(opt_name, longopt_xlate) val = getattr(self, opt_name) print " %s: %s" % (opt_name, val) 2) the 'config' target does not initialize all values. This is a known and fixed bug (fixed in version 1.0.1): import string,os from types import StringType class MyConfig(config): def finalize_options(self): """fix up types of option values. This is cut'n'paste from Distutils 1.0.1""" if self.include_dirs is None: self.include_dirs = self.distribution.include_dirs or [] elif type(self.include_dirs) is StringType: self.include_dirs = string.split(self.include_dirs, os.pathsep) if self.libraries is None: self.libraries = [] elif type(self.libraries) is StringType: self.libraries = [self.libraries] if self.library_dirs is None: self.library_dirs = [] elif type(self.library_dirs) is StringType: self.library_dirs = string.split(self.library_dirs, os.pathsep) 3) Use this only if you have man(1) files and you want to build RPM packages. The bdist_rpm command cannot handle man pages. Whats happening here? The rpm command calls python setup.py install --root=... --record=INSTALLED_FILES In INSTALLED_FILES are now all installed files listed inclusive a man page, for example ./usr/man/man1/myprog.1 But this man page gets compressed by rpm and we have now ./usr/man/man1/myprog.1.gz This makes subsequent 'rpm' commands fail which are based on the filenames found in INSTALLED_FILES. Below you see a quick and very dirty hack: just append ".gz" to all man file names in the INSTALLED_FILES index. Of course the proper solution would be to define multiple handler classes for all kinds of documentation (man pages, info pages, html pages ...). But thats a long way to go. from types import StringType import os,re class LCInstallData(install_data): """My own data installer to handle .man pages""" def run (self): self.mkpath(self.install_dir) for f in self.data_files: if type(f) == StringType: # it's a simple file, so copy it if self.warn_dir: self.warn("setup script did not provide a directory for " "'%s' -- installing right in '%s'" % (f, self.install_dir)) self._install_file(f, self.install_dir) else: # it's a tuple with path to install to and a list of files dir = f[0] if not os.path.isabs(dir): dir = os.path.join(self.install_dir, dir) elif self.root: dir = change_root(self.root, dir) self.mkpath(dir) for data in f[1]: self._install_file(data, dir) def _install_file(self, filename, dirname): (out, _) = self.copy_file(filename, dirname) # match for man pages .[0-9] if re.search(r'/man/.+\.\d$', out): out = out+".gz" self.outfiles.append(out)
participants (1)
-
Bastian Kleineidam