[Python-checkins] distutils2: branch merge
tarek.ziade
python-checkins at python.org
Sun Dec 26 14:21:44 CET 2010
tarek.ziade pushed 7eee7b1bb382 to distutils2:
http://hg.python.org/distutils2/rev/7eee7b1bb382
changeset: 838:7eee7b1bb382
parent: 837:001d7d14b6c7
parent: 836:a8eaafda8fd3
user: Alexis Metaireau <ametaireau at gmail.com>
date: Sun Nov 21 01:07:26 2010 +0000
summary:
branch merge
files:
distutils2/extension.py
diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -6,6 +6,8 @@
---------
- The setup runner supports more options:
+- XXX fill changes done in commands + compilers
+- Issue 10409: Fixed the Licence selector in mkcfg
1.0a3 - 2010-10-08
------------------
diff --git a/distutils2/command/__init__.py b/distutils2/command/__init__.py
--- a/distutils2/command/__init__.py
+++ b/distutils2/command/__init__.py
@@ -2,27 +2,52 @@
Package containing implementation of all the standard Distutils
commands."""
+from distutils2.errors import DistutilsModuleError
+from distutils2.util import resolve_name
+_COMMANDS = {
+ 'check': 'distutils2.command.check.check',
+ 'test': 'distutils2.command.test.test',
+ 'build': 'distutils2.command.build.build',
+ 'build_py': 'distutils2.command.build_py.build_py',
+ 'build_ext': 'distutils2.command.build_ext.build_ext',
+ 'build_clib': 'distutils2.command.build_clib.build_clib',
+ 'build_scripts': 'distutils2.command.build_scripts.build_scripts',
+ 'clean': 'distutils2.command.clean.clean',
+ 'install_dist': 'distutils2.command.install_dist.install_dist',
+ 'install_lib': 'distutils2.command.install_lib.install_lib',
+ 'install_headers': 'distutils2.command.install_headers.install_headers',
+ 'install_scripts': 'distutils2.command.install_scripts.install_scripts',
+ 'install_data': 'distutils2.command.install_data.install_data',
+ 'install_distinfo':
+ 'distutils2.command.install_distinfo.install_distinfo',
+ 'sdist': 'distutils2.command.sdist.sdist',
+ 'bdist': 'distutils2.command.bdist.bdist',
+ 'bdist_dumb': 'distutils2.command.bdist_dumb.bdist_dumb',
+ 'bdist_wininst': 'distutils2.command.bdist_wininst.bdist_wininst',
+ 'register': 'distutils2.command.register.register',
+ 'upload': 'distutils2.command.upload.upload',
+ 'upload_docs': 'distutils2.command.upload_docs.upload_docs'}
-__all__ = ['check',
- 'test',
- 'build',
- 'build_py',
- 'build_ext',
- 'build_clib',
- 'build_scripts',
- 'clean',
- 'install_dist',
- 'install_lib',
- 'install_headers',
- 'install_scripts',
- 'install_data',
- 'install_distinfo',
- 'sdist',
- 'bdist',
- 'bdist_dumb',
- 'bdist_wininst',
- 'register',
- 'upload',
- 'upload_docs'
- ]
+
+def get_command_names():
+ return sorted(_COMMANDS.keys())
+ """Return registered commands"""
+
+
+def set_command(location):
+ cls = resolve_name(location)
+ # XXX we want to do the duck-type checking here
+ _COMMANDS[cls.get_command_name()] = cls
+
+
+def get_command_class(name):
+ """Return the registered command"""
+ try:
+ cls = _COMMANDS[name]
+ if isinstance(cls, str):
+ cls = resolve_name(cls)
+ _COMMANDS[name] = cls
+ return cls
+ except KeyError:
+ raise DistutilsModuleError("Invalid command %s" % name)
diff --git a/distutils2/command/build.py b/distutils2/command/build.py
--- a/distutils2/command/build.py
+++ b/distutils2/command/build.py
@@ -127,27 +127,27 @@
# Run all relevant sub-commands. This will be some subset of:
# - build_py - pure Python modules
# - build_clib - standalone C libraries
- # - build_ext - Python extensions
- # - build_scripts - (Python) scripts
+ # - build_ext - Python extension modules
+ # - build_scripts - Python scripts
for cmd_name in self.get_sub_commands():
self.run_command(cmd_name)
# -- Predicates for the sub-command list ---------------------------
- def has_pure_modules (self):
+ def has_pure_modules(self):
return self.distribution.has_pure_modules()
- def has_c_libraries (self):
+ def has_c_libraries(self):
return self.distribution.has_c_libraries()
- def has_ext_modules (self):
+ def has_ext_modules(self):
return self.distribution.has_ext_modules()
- def has_scripts (self):
+ def has_scripts(self):
return self.distribution.has_scripts()
- sub_commands = [('build_py', has_pure_modules),
- ('build_clib', has_c_libraries),
- ('build_ext', has_ext_modules),
+ sub_commands = [('build_py', has_pure_modules),
+ ('build_clib', has_c_libraries),
+ ('build_ext', has_ext_modules),
('build_scripts', has_scripts),
]
diff --git a/distutils2/command/build_ext.py b/distutils2/command/build_ext.py
--- a/distutils2/command/build_ext.py
+++ b/distutils2/command/build_ext.py
@@ -14,12 +14,9 @@
DistutilsPlatformError, DistutilsSetupError)
from distutils2.compiler import customize_compiler, show_compilers
from distutils2.util import newer_group
-from distutils2.extension import Extension
+from distutils2.compiler.extension import Extension
from distutils2 import logger
-try:
- import sysconfig
-except ImportError:
- from distutils2._backport import sysconfig
+from distutils2._backport import sysconfig
# this keeps compatibility from 2.3 to 2.5
if sys.version < "2.6":
diff --git a/distutils2/command/build_scripts.py b/distutils2/command/build_scripts.py
--- a/distutils2/command/build_scripts.py
+++ b/distutils2/command/build_scripts.py
@@ -9,10 +9,7 @@
from distutils2.command.cmd import Command
from distutils2.util import convert_path, newer
from distutils2 import logger
-try:
- import sysconfig
-except ImportError:
- from distutils2._backport import sysconfig
+from distutils2._backport import sysconfig
from distutils2.compat import Mixin2to3
# check if Python is called on the first line with this expression
diff --git a/distutils2/command/cmd.py b/distutils2/command/cmd.py
--- a/distutils2/command/cmd.py
+++ b/distutils2/command/cmd.py
@@ -19,6 +19,7 @@
except ImportError:
from distutils2._backport.shutil import make_archive
+
class Command(object):
"""Abstract base class for defining command classes, the "worker bees"
of the Distutils. A useful analogy for command classes is to think of
@@ -57,7 +58,6 @@
pre_hook = None
post_hook = None
-
# -- Creation/initialization methods -------------------------------
def __init__(self, dist):
@@ -69,9 +69,9 @@
from distutils2.dist import Distribution
if not isinstance(dist, Distribution):
- raise TypeError, "dist must be a Distribution instance"
+ raise TypeError("dist must be a Distribution instance")
if self.__class__ is Command:
- raise RuntimeError, "Command is an abstract class"
+ raise RuntimeError("Command is an abstract class")
self.distribution = dist
self.initialize_options()
@@ -143,8 +143,8 @@
This method must be implemented by all command classes.
"""
- raise RuntimeError, \
- "abstract method -- subclass %s must override" % self.__class__
+ raise RuntimeError(
+ "abstract method -- subclass %s must override" % self.__class__)
def finalize_options(self):
"""Set final values for all the options that this command supports.
@@ -157,9 +157,8 @@
This method must be implemented by all command classes.
"""
- raise RuntimeError, \
- "abstract method -- subclass %s must override" % self.__class__
-
+ raise RuntimeError(
+ "abstract method -- subclass %s must override" % self.__class__)
def dump_options(self, header=None, indent=""):
if header is None:
@@ -184,8 +183,8 @@
This method must be implemented by all command classes.
"""
- raise RuntimeError, \
- "abstract method -- subclass %s must override" % self.__class__
+ raise RuntimeError(
+ "abstract method -- subclass %s must override" % self.__class__)
def announce(self, msg, level=logging.INFO):
"""If the current verbosity level is of greater than or equal to
@@ -237,8 +236,8 @@
setattr(self, option, default)
return default
elif not isinstance(val, str):
- raise DistutilsOptionError, \
- "'%s' must be a %s (got `%s`)" % (option, what, val)
+ raise DistutilsOptionError("'%s' must be a %s (got `%s`)" %
+ (option, what, val))
return val
def ensure_string(self, option, default=None):
@@ -248,7 +247,7 @@
self._ensure_stringlike(option, "string", default)
def ensure_string_list(self, option):
- """Ensure that 'option' is a list of strings. If 'option' is
+ r"""Ensure that 'option' is a list of strings. If 'option' is
currently a string, we split it either on /,\s*/ or /\s+/, so
"foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
["foo", "bar", "baz"].
@@ -270,17 +269,15 @@
ok = 0
if not ok:
- raise DistutilsOptionError, \
- "'%s' must be a list of strings (got %r)" % \
- (option, val)
-
+ raise DistutilsOptionError(
+ "'%s' must be a list of strings (got %r)" % (option, val))
def _ensure_tested_string(self, option, tester,
what, error_fmt, default=None):
val = self._ensure_stringlike(option, what, default)
if val is not None and not tester(val):
- raise DistutilsOptionError, \
- ("error in '%s' option: " + error_fmt) % (option, val)
+ raise DistutilsOptionError(
+ ("error in '%s' option: " + error_fmt) % (option, val))
def ensure_filename(self, option):
"""Ensure that 'option' is the name of an existing file."""
@@ -293,14 +290,14 @@
"directory name",
"'%s' does not exist or is not a directory")
-
# -- Convenience methods for commands ------------------------------
- def get_command_name(self):
- if hasattr(self, 'command_name'):
- return self.command_name
+ @classmethod
+ def get_command_name(cls):
+ if hasattr(cls, 'command_name'):
+ return cls.command_name
else:
- return self.__class__.__name__
+ return cls.__name__
def set_undefined_options(self, src_cmd, *options):
"""Set values of undefined options from another command.
@@ -368,12 +365,10 @@
commands.append(sub_command)
return commands
-
# -- External world manipulation -----------------------------------
def warn(self, msg):
- logger.warning("warning: %s: %s\n" %
- (self.get_command_name(), msg))
+ logger.warning("warning: %s: %s\n" % (self.get_command_name(), msg))
def execute(self, func, args, msg=None, level=1):
util.execute(func, args, msg, dry_run=self.dry_run)
@@ -412,19 +407,19 @@
and force flags.
"""
if self.dry_run:
- return # see if we want to display something
+ return # see if we want to display something
return copytree(infile, outfile, preserve_symlinks)
def move_file(self, src, dst, level=1):
"""Move a file respectin dry-run flag."""
if self.dry_run:
- return # XXX log ?
+ return # XXX log ?
return move(src, dst)
def spawn(self, cmd, search_path=1, level=1):
"""Spawn an external command respecting dry-run flag."""
from distutils2.util import spawn
- spawn(cmd, search_path, dry_run= self.dry_run)
+ spawn(cmd, search_path, dry_run=self.dry_run)
def make_archive(self, base_name, format, root_dir=None, base_dir=None,
owner=None, group=None):
@@ -449,12 +444,11 @@
if isinstance(infiles, str):
infiles = (infiles,)
elif not isinstance(infiles, (list, tuple)):
- raise TypeError, \
- "'infiles' must be a string, or a list or tuple of strings"
+ raise TypeError(
+ "'infiles' must be a string, or a list or tuple of strings")
if exec_msg is None:
- exec_msg = "generating %s from %s" % \
- (outfile, ', '.join(infiles))
+ exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles))
# If 'outfile' must be regenerated (either because it doesn't
# exist, is out-of-date, or the 'force' flag is true) then
diff --git a/distutils2/command/install_dist.py b/distutils2/command/install_dist.py
--- a/distutils2/command/install_dist.py
+++ b/distutils2/command/install_dist.py
@@ -520,7 +520,6 @@
raise DistutilsPlatformError("Can't install when "
"cross-compiling")
-
# Run all sub-commands (at least those that need to be run)
for cmd_name in self.get_sub_commands():
self.run_command(cmd_name)
diff --git a/distutils2/command/sdist.py b/distutils2/command/sdist.py
--- a/distutils2/command/sdist.py
+++ b/distutils2/command/sdist.py
@@ -15,6 +15,7 @@
except ImportError:
from distutils2._backport.shutil import get_archive_formats
+from distutils2.command import get_command_names
from distutils2.command.cmd import Command
from distutils2.errors import (DistutilsPlatformError, DistutilsOptionError,
DistutilsTemplateError, DistutilsModuleError)
@@ -250,7 +251,7 @@
if files:
self.filelist.extend(files)
- for cmd_name in self.distribution.get_command_names():
+ for cmd_name in get_command_names():
try:
cmd_obj = self.get_finalized_command(cmd_name)
except DistutilsOptionError:
diff --git a/distutils2/compiler/__init__.py b/distutils2/compiler/__init__.py
--- a/distutils2/compiler/__init__.py
+++ b/distutils2/compiler/__init__.py
@@ -4,7 +4,7 @@
from distutils2._backport import sysconfig
from distutils2.util import resolve_name
-from distutils2.errors import DistutilsModuleError, DistutilsPlatformError
+from distutils2.errors import DistutilsPlatformError
def customize_compiler(compiler):
@@ -13,7 +13,7 @@
Mainly needed on Unix, so we can plug in the information that
varies across Unices and is stored in Python's Makefile.
"""
- if compiler.compiler_type == "unix":
+ if compiler.name == "unix":
(cc, cxx, opt, cflags, ccshared, ldshared, so_ext, ar, ar_flags) = \
sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
'CCSHARED', 'LDSHARED', 'SO', 'AR',
@@ -105,16 +105,19 @@
return 'unix'
-_COMPILERS = {'unix': 'distutils2.compiler.unixccompiler.UnixCCompiler',
- 'msvc': 'distutils2.compiler.msvccompiler.MSVCCompiler',
- 'cygwin': 'distutils2.compiler.cygwinccompiler.CygWinCCompiler',
- 'mingw32': 'distutils2.compiler.cygwinccompiler.Mingw32CCompiler',
- 'bcpp': 'distutils2.compilers.bcppcompiler.BCPPCompiler'}
+_COMPILERS = {
+ 'unix': 'distutils2.compiler.unixccompiler.UnixCCompiler',
+ 'msvc': 'distutils2.compiler.msvccompiler.MSVCCompiler',
+ 'cygwin': 'distutils2.compiler.cygwinccompiler.CygwinCCompiler',
+ 'mingw32': 'distutils2.compiler.cygwinccompiler.Mingw32CCompiler',
+ 'bcpp': 'distutils2.compilers.bcppcompiler.BCPPCompiler'}
-def set_compiler(name, location):
+def set_compiler(location):
"""Add or change a compiler"""
- _COMPILERS[name] = location
+ cls = resolve_name(location)
+ # XXX we want to check the class here
+ _COMPILERS[cls.name] = cls
def show_compilers():
@@ -124,9 +127,12 @@
from distutils2.fancy_getopt import FancyGetopt
compilers = []
- for compiler, location in _COMPILERS.items():
- klass = resolve_name(location)
- compilers.append(("compiler=" + compiler, None, klass.description))
+ for name, cls in _COMPILERS.items():
+ if isinstance(cls, str):
+ cls = resolve_name(cls)
+ _COMPILERS[name] = cls
+
+ compilers.append(("compiler=" + name, None, cls.description))
compilers.sort()
pretty_printer = FancyGetopt(compilers)
@@ -151,19 +157,17 @@
if compiler is None:
compiler = get_default_compiler(plat)
- location = _COMPILERS[compiler]
+ cls = _COMPILERS[compiler]
except KeyError:
msg = "don't know how to compile C/C++ code on platform '%s'" % plat
if compiler is not None:
msg = msg + " with '%s' compiler" % compiler
raise DistutilsPlatformError(msg)
- try:
- cls = resolve_name(location)
- except ImportError:
- raise DistutilsModuleError(
- "can't compile C/C++ code: unable to load '%s'" % \
- location)
+ if isinstance(cls, str):
+ cls = resolve_name(cls)
+ _COMPILERS[compiler] = cls
+
# XXX The None is necessary to preserve backwards compatibility
# with classes that expect verbose to be the first positional
diff --git a/distutils2/compiler/bcppcompiler.py b/distutils2/compiler/bcppcompiler.py
--- a/distutils2/compiler/bcppcompiler.py
+++ b/distutils2/compiler/bcppcompiler.py
@@ -26,7 +26,7 @@
compiler, as defined by the CCompiler abstract class.
"""
- compiler_type = 'bcpp'
+ name = 'bcpp'
description = 'Borland C++ Compiler'
# Just set this so CCompiler's constructor doesn't barf. We currently
diff --git a/distutils2/compiler/ccompiler.py b/distutils2/compiler/ccompiler.py
--- a/distutils2/compiler/ccompiler.py
+++ b/distutils2/compiler/ccompiler.py
@@ -15,6 +15,7 @@
from distutils2 import logger
from distutils2.compiler import gen_preprocess_options
+
class CCompiler(object):
"""Abstract base class to define the interface that must be implemented
by real compiler classes. Also has some utility methods used by
@@ -29,11 +30,11 @@
attributes may be varied on a per-compilation or per-link basis.
"""
- # 'compiler_type' is a class attribute that identifies this class. It
+ # 'name' is a class attribute that identifies this class. It
# keeps code that wants to know what kind of compiler it's dealing with
# from having to import all possible compiler classes just to do an
# 'isinstance'.
- compiler_type = None
+ name = None
description = None
# XXX things not handled by this compiler abstraction model:
diff --git a/distutils2/compiler/cygwinccompiler.py b/distutils2/compiler/cygwinccompiler.py
--- a/distutils2/compiler/cygwinccompiler.py
+++ b/distutils2/compiler/cygwinccompiler.py
@@ -85,7 +85,7 @@
class CygwinCCompiler(UnixCCompiler):
""" Handles the Cygwin port of the GNU C compiler to Windows.
"""
- compiler_type = 'cygwin'
+ name = 'cygwin'
description = 'Cygwin port of GNU C Compiler for Win32'
obj_extension = ".o"
static_lib_extension = ".a"
@@ -110,7 +110,7 @@
self.gcc_version, self.ld_version, self.dllwrap_version = \
get_compiler_versions()
- self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
+ self.debug_print(self.name + ": gcc %s, ld %s, dllwrap %s\n" %
(self.gcc_version,
self.ld_version,
self.dllwrap_version) )
@@ -272,7 +272,8 @@
class Mingw32CCompiler(CygwinCCompiler):
""" Handles the Mingw32 port of the GNU C compiler to Windows.
"""
- compiler_type = 'mingw32'
+ name = 'mingw32'
+ description = 'MinGW32 compiler'
def __init__(self, verbose=0, dry_run=0, force=0):
diff --git a/distutils2/extension.py b/distutils2/compiler/extension.py
rename from distutils2/extension.py
rename to distutils2/compiler/extension.py
diff --git a/distutils2/compiler/msvc9compiler.py b/distutils2/compiler/msvc9compiler.py
--- a/distutils2/compiler/msvc9compiler.py
+++ b/distutils2/compiler/msvc9compiler.py
@@ -285,7 +285,7 @@
"""Concrete class that implements an interface to Microsoft Visual C++,
as defined by the CCompiler abstract class."""
- compiler_type = 'msvc'
+ name = 'msvc'
description = 'Microsoft Visual C++'
# Just set this so CCompiler's constructor doesn't barf. We currently
diff --git a/distutils2/compiler/msvccompiler.py b/distutils2/compiler/msvccompiler.py
--- a/distutils2/compiler/msvccompiler.py
+++ b/distutils2/compiler/msvccompiler.py
@@ -205,7 +205,7 @@
"""Concrete class that implements an interface to Microsoft Visual C++,
as defined by the CCompiler abstract class."""
- compiler_type = 'msvc'
+ name = 'msvc'
description = "Microsoft Visual C++"
# Just set this so CCompiler's constructor doesn't barf. We currently
diff --git a/distutils2/compiler/unixccompiler.py b/distutils2/compiler/unixccompiler.py
--- a/distutils2/compiler/unixccompiler.py
+++ b/distutils2/compiler/unixccompiler.py
@@ -106,7 +106,7 @@
class UnixCCompiler(CCompiler):
- compiler_type = 'unix'
+ name = 'unix'
description = 'Standard UNIX-style compiler'
# These are used by CCompiler in two places: the constructor sets
diff --git a/distutils2/config.py b/distutils2/config.py
--- a/distutils2/config.py
+++ b/distutils2/config.py
@@ -9,7 +9,7 @@
from distutils2 import logger
from distutils2.util import check_environ, resolve_name
from distutils2.compiler import set_compiler
-
+from distutils2.command import set_command
class Config(object):
"""Reads configuration files and work with the Distribution instance
@@ -94,20 +94,6 @@
self.setup_hook = resolve_name(setup_hook)
self.run_hook(content)
- if 'commands' in content['global']:
- commands = self._multiline(content['global']['commands'])
- if isinstance(commands, str):
- commands = [commands]
-
- for command in commands:
- command = command.split('=')
- if len(command) != 2:
- # Issue XXX a warning
- continue
- name, location = command[0].strip(), command[1].strip()
- self.dist.cmdclass[name] = resolve_name(location)
-
-
metadata = self.dist.metadata
# setting the metadata values
@@ -195,9 +181,12 @@
self._read_setup_cfg(parser)
for section in parser.sections():
- if section == 'compilers':
- self._load_compilers(parser.items(section))
- continue
+ if section == 'global':
+ if parser.has_option('global', 'compilers'):
+ self._load_compilers(parser.get('global', 'compilers'))
+
+ if parser.has_option('global', 'commands'):
+ self._load_commands(parser.get('global', 'commands'))
options = parser.options(section)
opt_dict = self.dist.get_option_dict(section)
@@ -247,5 +236,15 @@
raise DistutilsOptionError(msg)
def _load_compilers(self, compilers):
- for name, location in compilers:
- set_compiler(name, location)
+ compilers = self._multiline(compilers)
+ if isinstance(compilers, str):
+ compilers = [compilers]
+ for compiler in compilers:
+ set_compiler(compiler.strip())
+
+ def _load_commands(self, commands):
+ commands = self._multiline(commands)
+ if isinstance(commands, str):
+ commands = [commands]
+ for command in commands:
+ set_command(command.strip())
diff --git a/distutils2/dist.py b/distutils2/dist.py
--- a/distutils2/dist.py
+++ b/distutils2/dist.py
@@ -18,6 +18,7 @@
from distutils2 import logger
from distutils2.metadata import DistributionMetadata
from distutils2.config import Config
+from distutils2.command import get_command_class
# Regex to define acceptable Distutils command names. This is not *quite*
# the same as a Python NAME -- I don't allow leading underscores. The fact
@@ -153,14 +154,6 @@
# for the setup script to override command classes
self.cmdclass = {}
- # 'command_packages' is a list of packages in which commands
- # are searched for. The factory for command 'foo' is expected
- # to be named 'foo' in the module 'foo' in one of the packages
- # named here. This list is searched from the left; an error
- # is raised if no named package provides the command being
- # searched for. (Always access using get_command_packages().)
- self.command_packages = None
-
# 'script_name' and 'script_args' are usually set to sys.argv[0]
# and sys.argv[1:], but they can be overridden when the caller is
# not necessarily a setup script run from the command line.
@@ -388,11 +381,6 @@
commands=self.commands)
return
- # Oops, no commands found -- an end-user error
- if not self.commands:
- raise DistutilsArgError("no commands supplied")
-
- # All is well: return true
return 1
def _get_toplevel_options(self):
@@ -401,10 +389,7 @@
This includes options that are recognized *only* at the top
level as well as options recognized for commands.
"""
- return self.global_options + [
- ("command-packages=", None,
- "list of packages that provide distutils commands"),
- ]
+ return self.global_options
def _parse_command_opts(self, parser, args):
"""Parse the command-line options for a single command.
@@ -425,17 +410,19 @@
# 1) know that it's a valid command, and 2) know which options
# it takes.
try:
- cmd_class = self.get_command_class(command)
+ cmd_class = get_command_class(command)
except DistutilsModuleError, msg:
raise DistutilsArgError(msg)
+ # XXX We want to push this in distutils.command
+ #
# Require that the command class be derived from Command -- want
# to be sure that the basic "command" interface is implemented.
for meth in ('initialize_options', 'finalize_options', 'run'):
if hasattr(cmd_class, meth):
continue
raise DistutilsClassError(
- 'command "%s" must implement "%s"' % (cmd_class. meth))
+ 'command "%s" must implement "%s"' % (cmd_class, meth))
# Also make sure that the command object provides a list of its
# known options.
@@ -545,7 +532,7 @@
if isinstance(command, type) and issubclass(command, Command):
cls = command
else:
- cls = self.get_command_class(command)
+ cls = get_command_class(command)
if (hasattr(cls, 'help_options') and
isinstance(cls.help_options, list)):
parser.set_option_table(cls.user_options +
@@ -606,7 +593,7 @@
for cmd in commands:
cls = self.cmdclass.get(cmd)
if not cls:
- cls = self.get_command_class(cmd)
+ cls = get_command_class(cmd)
try:
description = cls.description
except AttributeError:
@@ -648,94 +635,9 @@
"Extra commands",
max_length)
- def get_command_list(self):
- """Get a list of (command, description) tuples.
-
- The list is divided into standard commands (listed in
- distutils2.command.__all__) and extra commands (given in
- self.cmdclass and not standard commands). The descriptions come
- from the command class attribute 'description'.
- """
- # Currently this is only used on Mac OS, for the Mac-only GUI
- # Distutils interface (by Jack Jansen)
-
- rv = []
- for cls in self.get_command_classes():
- try:
- description = cls.description
- except AttributeError:
- description = "(no description available)"
- rv.append((cls, description))
- return rv
# -- Command class/object methods ----------------------------------
- def get_command_packages(self):
- """Return a list of packages from which commands are loaded."""
- pkgs = self.command_packages
- if not isinstance(pkgs, list):
- if pkgs is None:
- pkgs = ''
- pkgs = [pkg.strip() for pkg in pkgs.split(',') if pkg != '']
- if "distutils2.command" not in pkgs:
- pkgs.insert(0, "distutils2.command")
- self.command_packages = pkgs
- return pkgs
-
- def get_command_names(self):
- """Return a list of all command names."""
- return [getattr(cls, 'command_name', cls.__name__)
- for cls in self.get_command_classes()]
-
- def get_command_classes(self):
- """Return a list of all command classes."""
- std_commands, extra_commands = self._get_command_groups()
- classes = []
- for cmd in (std_commands + extra_commands):
- try:
- cls = self.cmdclass[cmd]
- except KeyError:
- cls = self.get_command_class(cmd)
- classes.append(cls)
- return classes
-
- def get_command_class(self, command):
- """Return the class that implements the Distutils command named by
- 'command'. First we check the 'cmdclass' dictionary; if the
- command is mentioned there, we fetch the class object from the
- dictionary and return it. Otherwise we load the command module
- ("distutils.command." + command) and fetch the command class from
- the module. The loaded class is also stored in 'cmdclass'
- to speed future calls to 'get_command_class()'.
-
- Raises DistutilsModuleError if the expected module could not be
- found, or if that module does not define the expected class.
- """
- cls = self.cmdclass.get(command)
- if cls:
- return cls
-
- for pkgname in self.get_command_packages():
- module_name = "%s.%s" % (pkgname, command)
- class_name = command
-
- try:
- __import__(module_name)
- module = sys.modules[module_name]
- except ImportError:
- continue
-
- try:
- cls = getattr(module, class_name)
- except AttributeError:
- raise DistutilsModuleError(
- "invalid command '%s' (no class '%s' in module '%s')" %
- (command, class_name, module_name))
-
- self.cmdclass[command] = cls
- return cls
-
- raise DistutilsModuleError("invalid command '%s'" % command)
def get_command_obj(self, command, create=1):
"""Return the command object for 'command'. Normally this object
@@ -748,7 +650,7 @@
logger.debug("Distribution.get_command_obj(): " \
"creating '%s' command object" % command)
- cls = self.get_command_class(command)
+ cls = get_command_class(command)
cmd_obj = self.command_obj[command] = cls(self)
self.have_run[command] = 0
diff --git a/distutils2/mkcfg.py b/distutils2/mkcfg.py
--- a/distutils2/mkcfg.py
+++ b/distutils2/mkcfg.py
@@ -148,6 +148,16 @@
CLASSIFIERS = _build_classifiers_dict(_CLASSIFIERS_LIST)
+def _build_licences(classifiers):
+ res = []
+ for index, item in enumerate(classifiers):
+ if not item.startswith('License :: '):
+ continue
+ res.append((index, item.split(' :: ')[-1].lower()))
+ return res
+
+LICENCES = _build_licences(_CLASSIFIERS_LIST)
+
class MainProgram(object):
def __init__(self):
@@ -378,45 +388,44 @@
if not license:
return
- licenseWords = license.lower().split(' ')
+ license_words = license.lower().split(' ')
+ found_list = []
- foundList = []
- # TODO use enumerate
- for index in range(len(_CLASSIFIERS_LIST)):
- troveItem = _CLASSIFIERS_LIST[index]
- if not troveItem.startswith('License :: '):
- continue
- troveItem = troveItem[11:].lower()
+ for index, licence in LICENCES:
+ for word in license_words:
+ if word in licence:
+ found_list.append(index)
+ break
- allMatch = True
- for word in licenseWords:
- if not word in troveItem:
- allMatch = False
- break
- if allMatch:
- foundList.append(index)
+ if len(found_list) == 0:
+ print('ERROR: Could not find a matching license for "%s"' % \
+ license)
+ continue
question = 'Matching licenses:\n\n'
- # TODO use enumerate?
- for i in xrange(1, len(foundList) + 1):
- question += ' %s) %s\n' % (i, _CLASSIFIERS_LIST[foundList[i - 1]])
+
+ for index, list_index in enumerate(found_list):
+ question += ' %s) %s\n' % (index + 1,
+ _CLASSIFIERS_LIST[list_index])
+
question += ('\nType the number of the license you wish to use or '
'? to try again:')
- troveLicense = ask(question, required=False)
+ choice = ask(question, required=False)
- if troveLicense == '?':
+ if choice == '?':
continue
- if troveLicense == '':
+ if choice == '':
return
- # FIXME the int conversion can fail
- foundIndex = foundList[int(troveLicense) - 1]
- classifiers[_CLASSIFIERS_LIST[foundIndex]] = 1
+
try:
- return
- except IndexError:
+ index = found_list[int(choice) - 1]
+ except ValueError:
print ("ERROR: Invalid selection, type a number from the list "
"above.")
+ classifiers[_CLASSIFIERS_LIST[index]] = 1
+ return
+
def set_devel_status(self, classifiers):
while True:
choice = ask(dedent('''\
diff --git a/distutils2/run.py b/distutils2/run.py
--- a/distutils2/run.py
+++ b/distutils2/run.py
@@ -1,10 +1,12 @@
import os
import sys
+from optparse import OptionParser
from distutils2.util import grok_environment_error
from distutils2.errors import (DistutilsSetupError, DistutilsArgError,
DistutilsError, CCompilerError)
from distutils2.dist import Distribution
+from distutils2 import __version__
# This is a barebones help message generated displayed when the user
# runs the setup script with no arguments at all. More useful help
@@ -23,7 +25,7 @@
return USAGE % {'script': script}
-def main(**attrs):
+def commands_main(**attrs):
"""The gateway to the Distutils: do everything your setup script needs
to do, in a highly flexible and user-driven way. Briefly: create a
Distribution instance; find and parse config files; parse the command
@@ -110,5 +112,24 @@
return dist
+def main():
+ """Main entry point for Distutils2"""
+ parser = OptionParser()
+ parser.disable_interspersed_args()
+ parser.add_option("-v", "--version",
+ action="store_true", dest="version", default=False,
+ help="Prints out the version of Distutils2 and exits.")
+
+ options, args = parser.parse_args()
+ if options.version:
+ print('Distutils2 %s' % __version__)
+ sys.exit(0)
+
+ if len(args) == 0:
+ parser.print_help()
+
+ commands_main()
+ sys.exit(0)
+
if __name__ == '__main__':
main()
diff --git a/distutils2/tests/test_command_build.py b/distutils2/tests/test_command_build.py
--- a/distutils2/tests/test_command_build.py
+++ b/distutils2/tests/test_command_build.py
@@ -4,10 +4,7 @@
from distutils2.command.build import build
from distutils2.tests import unittest, support
-try:
- from sysconfig import get_platform
-except ImportError:
- from distutils2._backport.sysconfig import get_platform
+from distutils2._backport.sysconfig import get_platform
class BuildTestCase(support.TempdirManager,
support.LoggingCatcher,
diff --git a/distutils2/tests/test_command_build_ext.py b/distutils2/tests/test_command_build_ext.py
--- a/distutils2/tests/test_command_build_ext.py
+++ b/distutils2/tests/test_command_build_ext.py
@@ -5,17 +5,13 @@
import distutils2.tests
from distutils2.tests import unittest
-from distutils2.extension import Extension
+from distutils2.compiler.extension import Extension
from distutils2.dist import Distribution
from distutils2.command.build_ext import build_ext
from distutils2.tests import support
-from distutils2.extension import Extension
from distutils2.errors import (UnknownFileError, DistutilsSetupError,
CompileError)
-try:
- import sysconfig
-except ImportError:
- from distutils2._backport import sysconfig
+from distutils2._backport import sysconfig
# http://bugs.python.org/issue4373
@@ -107,10 +103,7 @@
old = sys.platform
sys.platform = 'sunos' # fooling finalize_options
- try:
- from sysconfig import _CONFIG_VARS
- except ImportError:
- from distutils2._backport.sysconfig import _CONFIG_VARS
+ from distutils2._backport.sysconfig import _CONFIG_VARS
old_var = _CONFIG_VARS.get('Py_ENABLE_SHARED')
_CONFIG_VARS['Py_ENABLE_SHARED'] = 1
diff --git a/distutils2/tests/test_command_build_scripts.py b/distutils2/tests/test_command_build_scripts.py
--- a/distutils2/tests/test_command_build_scripts.py
+++ b/distutils2/tests/test_command_build_scripts.py
@@ -4,10 +4,7 @@
from distutils2.command.build_scripts import build_scripts
from distutils2.dist import Distribution
-try:
- import sysconfig
-except ImportError:
- from distutils2._backport import sysconfig
+from distutils2._backport import sysconfig
from distutils2.tests import unittest, support
diff --git a/distutils2/tests/test_command_install_dist.py b/distutils2/tests/test_command_install_dist.py
--- a/distutils2/tests/test_command_install_dist.py
+++ b/distutils2/tests/test_command_install_dist.py
@@ -19,6 +19,7 @@
from distutils2.tests import unittest, support
+
class InstallTestCase(support.TempdirManager,
support.EnvironGuard,
support.LoggingCatcher,
@@ -83,10 +84,12 @@
_CONFIG_VARS['userbase'] = self.user_base
scheme = '%s_user' % os.name
_SCHEMES.set(scheme, 'purelib', self.user_site)
+
def _expanduser(path):
if path[0] == '~':
path = os.path.normpath(self.tmpdir) + path[1:]
return path
+
self.old_expand = os.path.expanduser
os.path.expanduser = _expanduser
@@ -212,6 +215,7 @@
install_module.DEBUG = False
self.assertTrue(len(self.logs) > old_logs_len)
+
def test_suite():
return unittest.makeSuite(InstallTestCase)
diff --git a/distutils2/tests/test_command_install_lib.py b/distutils2/tests/test_command_install_lib.py
--- a/distutils2/tests/test_command_install_lib.py
+++ b/distutils2/tests/test_command_install_lib.py
@@ -3,7 +3,7 @@
import os
from distutils2.command.install_lib import install_lib
-from distutils2.extension import Extension
+from distutils2.compiler.extension import Extension
from distutils2.tests import unittest, support
from distutils2.errors import DistutilsOptionError
diff --git a/distutils2/tests/test_command_test.py b/distutils2/tests/test_command_test.py
--- a/distutils2/tests/test_command_test.py
+++ b/distutils2/tests/test_command_test.py
@@ -9,10 +9,11 @@
from operator import getitem, setitem, delitem
from StringIO import StringIO
-from distutils2.command.cmd import Command
+from distutils2.command.build import build
from distutils2.tests import unittest
from distutils2.tests.support import TempdirManager, LoggingCatcher
from distutils2.command.test import test
+from distutils2.command import set_command
from distutils2.dist import Distribution
from distutils2._backport import pkgutil
@@ -31,6 +32,17 @@
here = os.path.dirname(os.path.abspath(__file__))
+_RECORD = []
+
+class MockBuildCmd(build):
+ build_lib = "mock build lib"
+ command_name = 'build'
+ plat_name = 'whatever'
+ def initialize_options(self): pass
+ def finalize_options(self): pass
+ def run(self): _RECORD.append("build run")
+
+
class TestTest(TempdirManager,
LoggingCatcher,
unittest.TestCase):
@@ -111,20 +123,17 @@
self.assertEqual(record, ["suite", "run"])
def test_builds_before_running_tests(self):
- dist = Distribution()
- cmd = test(dist)
- cmd.runner = self.prepare_named_function(lambda: None)
- record = []
- class MockBuildCmd(Command):
- build_lib = "mock build lib"
- def initialize_options(self): pass
- def finalize_options(self): pass
- def run(self): record.append("build run")
- dist.cmdclass['build'] = MockBuildCmd
-
- cmd.ensure_finalized()
- cmd.run()
- self.assertEqual(record, ['build run'])
+ set_command('distutils2.tests.test_command_test.MockBuildCmd')
+ try:
+ dist = Distribution()
+ cmd = test(dist)
+ cmd.runner = self.prepare_named_function(lambda: None)
+ _RECORD[:] = []
+ cmd.ensure_finalized()
+ cmd.run()
+ self.assertEqual(_RECORD, ['build run'])
+ finally:
+ set_command('distutils2.command.build.build')
def _test_works_with_2to3(self):
pass
@@ -157,7 +166,6 @@
def test_custom_runner(self):
dist = Distribution()
cmd = test(dist)
-
record = []
cmd.runner = self.prepare_named_function(lambda: record.append("runner called"))
cmd.ensure_finalized()
@@ -189,12 +197,12 @@
def test_calls_discover(self):
self.safely_replace(ut1.TestLoader, "discover", delete=True)
mock_ut2 = self.prepare_mock_ut2()
- record = []
- mock_ut2.TestLoader.discover = lambda self, path: record.append(path)
+ _RECORD[:] = []
+ mock_ut2.TestLoader.discover = lambda self, path: _RECORD.append(path)
dist = Distribution()
cmd = test(dist)
cmd.run()
- self.assertEqual(record, [os.curdir])
+ self.assertEqual(_RECORD, [os.curdir])
def test_suite():
return unittest.makeSuite(TestTest)
diff --git a/distutils2/tests/test_compiler.py b/distutils2/tests/test_compiler.py
--- a/distutils2/tests/test_compiler.py
+++ b/distutils2/tests/test_compiler.py
@@ -7,6 +7,10 @@
class FakeCompiler(object):
+
+ name = 'fake'
+ description = 'Fake'
+
def library_dir_option(self, dir):
return "-L" + dir
@@ -33,7 +37,7 @@
# make sure AR gets caught
class compiler:
- compiler_type = 'unix'
+ name = 'unix'
def set_executables(self, **kw):
self.exes = kw
diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py
--- a/distutils2/tests/test_config.py
+++ b/distutils2/tests/test_config.py
@@ -74,20 +74,22 @@
[global]
commands =
- foo = distutils2.tests.test_config.Foo
+ distutils2.tests.test_config.FooBarBazTest
+
+compilers =
+ distutils2.tests.test_config.DCompiler
setup_hook = distutils2.tests.test_config.hook
+
+
[install_dist]
sub_commands = foo
-
-[compilers]
-d = distutils2.tests.test_config.DCompiler
"""
class DCompiler(object):
- compiler_type = 'd'
+ name = 'd'
description = 'D Compiler'
def __init__(self, *args):
@@ -97,21 +99,29 @@
content['metadata']['version'] += '.dev1'
-class Foo(object):
+class FooBarBazTest(object):
def __init__(self, dist):
self.distribution = dist
+ @classmethod
+ def get_command_name(self):
+ return 'foo'
+
def run(self):
self.distribution.foo_was_here = 1
def nothing(self):
pass
+ def get_source_files(self):
+ return []
+
ensure_finalized = finalize_options = initialize_options = nothing
class ConfigTestCase(support.TempdirManager,
+ support.LoggingCatcher,
unittest.TestCase):
def setUp(self):
@@ -183,8 +193,15 @@
('/etc/init.d ', ['init-script'])])
self.assertEqual(dist.package_dir['two'], 'src')
- # make sure we get the foo command loaded !
- self.assertEquals(dist.cmdclass['foo'], Foo)
+ # Make sure we get the foo command loaded. We use a string comparison
+ # instead of assertIsInstance because the class is not the same when
+ # this test is run directly: foo is distutils2.tests.test_config.Foo
+ # because get_command_class uses the full name, but a bare "Foo" in
+ # this file would be __main__.Foo when run as "python test_config.py".
+ # The name FooBarBazTest should be unique enough to prevent
+ # collisions.
+ self.assertEqual(dist.get_command_obj('foo').__class__.__name__,
+ 'FooBarBazTest')
# did the README got loaded ?
self.assertEquals(dist.metadata['description'], 'yeah')
diff --git a/distutils2/tests/test_cygwinccompiler.py b/distutils2/tests/test_cygwinccompiler.py
--- a/distutils2/tests/test_cygwinccompiler.py
+++ b/distutils2/tests/test_cygwinccompiler.py
@@ -1,10 +1,8 @@
"""Tests for distutils.cygwinccompiler."""
import sys
import os
-try:
- import sysconfig
-except ImportError:
- from distutils2._backport import sysconfig
+
+from distutils2._backport import sysconfig
from distutils2.tests import run_unittest
from distutils2.tests import captured_stdout
diff --git a/distutils2/tests/test_dist.py b/distutils2/tests/test_dist.py
--- a/distutils2/tests/test_dist.py
+++ b/distutils2/tests/test_dist.py
@@ -8,6 +8,7 @@
import distutils2.dist
from distutils2.dist import Distribution, fix_help_options
+from distutils2.command import set_command
from distutils2.command.cmd import Command
from distutils2.errors import DistutilsModuleError, DistutilsOptionError
from distutils2.tests import TESTFN, captured_stdout
@@ -66,52 +67,6 @@
finally:
distutils2.dist.DEBUG = False
- def test_command_packages_unspecified(self):
- sys.argv.append("build")
- d = create_distribution()
- self.assertEqual(d.get_command_packages(), ["distutils2.command"])
-
- def test_command_packages_cmdline(self):
- from distutils2.tests.test_dist import test_dist
- sys.argv.extend(["--command-packages",
- "foo.bar,distutils2.tests",
- "test_dist",
- "-Ssometext",
- ])
- d = create_distribution()
- # let's actually try to load our test command:
- self.assertEqual(d.get_command_packages(),
- ["distutils2.command", "foo.bar", "distutils2.tests"])
- cmd = d.get_command_obj("test_dist")
- self.assertTrue(isinstance(cmd, test_dist))
- self.assertEqual(cmd.sample_option, "sometext")
-
- def test_command_packages_configfile(self):
- sys.argv.append("build")
- f = open(TESTFN, "w")
- try:
- print >> f, "[global]"
- print >> f, "command_packages = foo.bar, splat"
- f.close()
- d = create_distribution([TESTFN])
- self.assertEqual(d.get_command_packages(),
- ["distutils2.command", "foo.bar", "splat"])
-
- # ensure command line overrides config:
- sys.argv[1:] = ["--command-packages", "spork", "build"]
- d = create_distribution([TESTFN])
- self.assertEqual(d.get_command_packages(),
- ["distutils2.command", "spork"])
-
- # Setting --command-packages to '' should cause the default to
- # be used even if a config file specified something else:
- sys.argv[1:] = ["--command-packages", "", "build"]
- d = create_distribution([TESTFN])
- self.assertEqual(d.get_command_packages(), ["distutils2.command"])
-
- finally:
- os.unlink(TESTFN)
-
def test_write_pkg_file(self):
# Check DistributionMetadata handling of Unicode fields
tmp_dir = self.mkdtemp()
@@ -188,18 +143,6 @@
self.assertEqual(dist.metadata['platform'], ['one', 'two'])
self.assertEqual(dist.metadata['keywords'], ['one', 'two'])
- def test_get_command_packages(self):
- dist = Distribution()
- self.assertEqual(dist.command_packages, None)
- cmds = dist.get_command_packages()
- self.assertEqual(cmds, ['distutils2.command'])
- self.assertEqual(dist.command_packages,
- ['distutils2.command'])
-
- dist.command_packages = 'one,two'
- cmds = dist.get_command_packages()
- self.assertEqual(cmds, ['distutils2.command', 'one', 'two'])
-
def test_announce(self):
# make sure the level is known
dist = Distribution()
@@ -250,12 +193,9 @@
self.write_file((temp_home, "config2.cfg"),
'[test_dist]\npre-hook.b = type')
- sys.argv.extend(["--command-packages",
- "distutils2.tests",
- "test_dist"])
+ set_command('distutils2.tests.test_dist.test_dist')
dist = create_distribution(config_files)
cmd = dist.get_command_obj("test_dist")
-
self.assertEqual(cmd.pre_hook, {"a": 'type', "b": 'type'})
def test_hooks_get_run(self):
@@ -278,10 +218,7 @@
record.append('post-%s' % cmd.get_command_name())
'''))
- sys.argv.extend(["--command-packages",
- "distutils2.tests",
- "test_dist"])
-
+ set_command('distutils2.tests.test_dist.test_dist')
d = create_distribution([config_file])
cmd = d.get_command_obj("test_dist")
@@ -311,10 +248,7 @@
[test_dist]
pre-hook.test = nonexistent.dotted.name'''))
- sys.argv.extend(["--command-packages",
- "distutils2.tests",
- "test_dist"])
-
+ set_command('distutils2.tests.test_dist.test_dist')
d = create_distribution([config_file])
cmd = d.get_command_obj("test_dist")
cmd.ensure_finalized()
@@ -329,10 +263,7 @@
[test_dist]
pre-hook.test = distutils2.tests.test_dist.__doc__'''))
- sys.argv.extend(["--command-packages",
- "distutils2.tests",
- "test_dist"])
-
+ set_command('distutils2.tests.test_dist.test_dist')
d = create_distribution([config_file])
cmd = d.get_command_obj("test_dist")
cmd.ensure_finalized()
diff --git a/distutils2/tests/test_extension.py b/distutils2/tests/test_extension.py
--- a/distutils2/tests/test_extension.py
+++ b/distutils2/tests/test_extension.py
@@ -1,7 +1,7 @@
"""Tests for distutils.extension."""
import os
-from distutils2.extension import Extension
+from distutils2.compiler.extension import Extension
from distutils2.tests import unittest
class ExtensionTestCase(unittest.TestCase):
diff --git a/distutils2/tests/test_index_simple.py b/distutils2/tests/test_index_simple.py
--- a/distutils2/tests/test_index_simple.py
+++ b/distutils2/tests/test_index_simple.py
@@ -250,7 +250,7 @@
# Test that the simple link matcher yield the good links.
generator = crawler._simple_link_matcher(content, crawler.index_url)
- self.assertEqual(('%stest/foobar-1.tar.gz#md5=abcdef' % crawler.index_url,
+ self.assertEqual(('%stest/foobar-1.tar.gz#md5=abcdef' % crawler.index_url,
True), generator.next())
self.assertEqual(('http://dl-link1', True), generator.next())
self.assertEqual(('%stest' % crawler.index_url, False),
@@ -260,7 +260,7 @@
# Follow the external links is possible (eg. homepages)
crawler.follow_externals = True
generator = crawler._simple_link_matcher(content, crawler.index_url)
- self.assertEqual(('%stest/foobar-1.tar.gz#md5=abcdef' % crawler.index_url,
+ self.assertEqual(('%stest/foobar-1.tar.gz#md5=abcdef' % crawler.index_url,
True), generator.next())
self.assertEqual(('http://dl-link1', True), generator.next())
self.assertEqual(('http://dl-link2', False), generator.next())
@@ -304,8 +304,8 @@
# we can search the index for some projects, on their names
# the case used no matters here
crawler = self._get_simple_crawler(server)
- tests = (('Foobar', ['FooBar-bar', 'Foobar-baz', 'Baz-FooBar']),
- ('foobar*', ['FooBar-bar', 'Foobar-baz']),
+ tests = (('Foobar', ['FooBar-bar', 'Foobar-baz', 'Baz-FooBar']),
+ ('foobar*', ['FooBar-bar', 'Foobar-baz']),
('*foobar', ['Baz-FooBar',]))
for search, expected in tests:
diff --git a/distutils2/tests/test_metadata.py b/distutils2/tests/test_metadata.py
--- a/distutils2/tests/test_metadata.py
+++ b/distutils2/tests/test_metadata.py
@@ -11,6 +11,7 @@
from distutils2.errors import (MetadataConflictError,
MetadataUnrecognizedVersionError)
+
class DistributionMetadataTestCase(LoggingCatcher, WarningsCatcher,
unittest.TestCase):
@@ -95,7 +96,6 @@
{'python_version': '0.1'}))
def test_metadata_read_write(self):
-
PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
metadata = DistributionMetadata(PKG_INFO)
out = StringIO()
diff --git a/distutils2/tests/test_unixccompiler.py b/distutils2/tests/test_unixccompiler.py
--- a/distutils2/tests/test_unixccompiler.py
+++ b/distutils2/tests/test_unixccompiler.py
@@ -1,11 +1,7 @@
"""Tests for distutils.unixccompiler."""
import sys
-try:
- import sysconfig
-except ImportError:
- from distutils2._backport import sysconfig
-
+from distutils2._backport import sysconfig
from distutils2.compiler.unixccompiler import UnixCCompiler
from distutils2.tests import unittest
diff --git a/distutils2/util.py b/distutils2/util.py
--- a/distutils2/util.py
+++ b/distutils2/util.py
@@ -659,8 +659,8 @@
for part in parts[1:]:
try:
ret = getattr(ret, part)
- except AttributeError:
- raise ImportError
+ except AttributeError, exc:
+ raise ImportError(exc)
return ret
diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst
new file mode 100644
--- /dev/null
+++ b/docs/source/setupcfg.rst
@@ -0,0 +1,161 @@
+==================
+The setup.cfg file
+==================
+
+This document describes the :file:`setup.cfg`, a ini-like file used by
+Distutils2 to replace the :file:`setup.py` file.
+
+Each section contains a description of its options.
+
+- Options that are marked *\*multi* can have multiple values, one value
+ per line.
+- Options that are marked *\*optional* can be omited.
+- Options that are marked *\*environ* can use environement markes, as described
+ in PEP 345.
+
+The sections are:
+
+- global
+- metadata
+- files
+- command sections
+
+
+global
+======
+
+Contains global options for Distutils2. This section is shared with Distutils1.
+
+- **commands**: Defined Distutils2 command. A command is defined by its fully
+ qualified name.
+
+ Examples::
+
+ [global]
+ commands =
+ package.sdist.CustomSdistCommand
+
+ *\*optional* *\*multi*
+
+- **compilers**: Defined Distutils2 compiler. A compiler is defined by its fully
+ qualified name.
+
+ Example::
+
+ [global]
+ compiler =
+ package.compilers.CustomCCompiler
+
+ *\*optional* *\*multi*
+
+- **setup_hook**: defines a callable that will be called right after the
+ :file:`setup.cfg` file is read. The callable receives the configuration
+ in form of a mapping and can make some changes to it. *\*optional*
+
+
+metadata
+========
+
+The metadata section contains the metadata for the project as described in
+PEP 345.
+
+
+Fields:
+
+- **name**: Name of the project.
+- **version**: Version of the project. Must comply with PEP 386.
+- **platform**: Platform specification describing an operating system supported
+ by the distribution which is not listed in the "Operating System" Trove
+ classifiers. *\*multi* *\*optional*
+- **supported-platform**: Binary distributions containing a PKG-INFO file will
+ use the Supported-Platform field in their metadata to specify the OS and
+ CPU for which the binary distribution was compiled. The semantics of
+ the Supported-Platform field are freeform. *\*multi* *\*optional*
+- **summary**: A one-line summary of what the distribution does.
+ (Used to be called *description* in Distutils1.)
+- **description**: A longer description. (Used to be called *long_description*
+ in Distutils1.) A file can be provided in the *description-file* field.
+ *\*optional*
+- **description-file**: path to a text file that will be used for the
+ **description** field. *\*optional*
+- **keywords**: A list of additional keywords to be used to assist searching
+ for the distribution in a larger catalog. Comma or space-separated. *\*optional*
+- **home-page**: The URL for the distribution's home page.
+- **download-url**: The URL from which this version of the distribution
+ can be downloaded. *\*optional*
+- **author**: Author's name. *\*optional*
+- **author-email**: Author's e-mail. *\*optional*
+- **maintainer**: Maintainer's name. *\*optional*
+- **maintainer-email**: Maintainer's e-mail. *\*optional*
+- **license**: A text indicating the term of uses, when a trove classifier does
+ not match. *\*optional*.
+- **classifiers**: Classification for the distribution, as described in PEP 301.
+ *\*optional* *\*multi* *\*environ*
+- **requires-dist**: name of another distutils project required as a dependency.
+ The format is *name (version)* where version is an optional
+ version declaration, as described in PEP 345. *\*optional* *\*multi* *\*environ*
+- **provides-dist**: name of another distutils project contained whithin this
+ distribution. Same format than *requires-dist*. *\*optional* *\*multi* *\*environ*
+- **obsoletes-dist**: name of another distutils project this version obsoletes.
+ Same format than *requires-dist*. *\*optional* *\*multi* *\*environ*
+- **requires-python**: Specifies the Python version the distribution requires.
+ The value is a version number, as described in PEP 345.
+ *\*optional* *\*multi* *\*environ*
+- **requires-externals**: a dependency in the system. This field is free-form,
+ and just a hint for downstream maintainers. *\*optional* *\*multi* *\*environ*
+- **project-url**: A label, followed by a browsable URL for the project.
+ "label, url". The label is limited to 32 signs. *\*optional* *\*multi*
+
+
+Example::
+
+ [metadata]
+ name = pypi2rpm
+ version = 0.1
+ author = Tarek Ziade
+ author_email = tarek at ziade.org
+ summary = Script that transforms a sdist archive into a rpm archive
+ description-file = README
+ home_page = http://bitbucket.org/tarek/pypi2rpm
+
+ classifier = Development Status :: 3 - Alpha
+ License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)
+
+
+
+files
+=====
+
+This section describes the files included in the project.
+
+- **packages**: a list of packages the project includes *\*optional* *\*multi*
+- **modules**: a list of packages the project includes *\*optional* *\*multi*
+- **scripts**: a list of scripts the project includes *\*optional* *\*multi*
+- **extra_files**: a list of patterns to include extra files *\*optional* *\*multi*
+
+Example::
+
+ [files]
+ packages =
+ pypi2rpm
+ pypi2rpm.command
+
+ scripts =
+ pypi2rpm/pypi2rpm.py
+
+ extra_files =
+ setup.py
+
+
+command sections
+================
+
+Each command can have its options described in :file:`setup.cfg`
+
+
+Example::
+
+ [sdist]
+ manifest_makers = package.module.Maker
+
+
--
Repository URL: http://hg.python.org/distutils2
More information about the Python-checkins
mailing list