summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPJ Eby <distutils-sig@python.org>2005-08-06 18:46:28 +0000
committerPJ Eby <distutils-sig@python.org>2005-08-06 18:46:28 +0000
commit8a29467d941a7983d5f6eadc5c0e1624417944b6 (patch)
treeb270afe3a01c9bead94060de3c3adfa590bd933f
parenta762d97ea517f64a405d82ad7acaa85d3eb30c39 (diff)
downloadpython-setuptools-git-8a29467d941a7983d5f6eadc5c0e1624417944b6.tar.gz
Enhanced setuptools infrastructure to support distutils extensions that
can be plugged in at setup() time to define new setup() arguments or distutils commands. This allows modularization and reuse of distutils extensions in a way that was previously not possible. --HG-- branch : setuptools extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4041180
-rwxr-xr-xsetup.py12
-rwxr-xr-xsetuptools.egg-info/entry_points.txt13
-rwxr-xr-xsetuptools.txt136
-rw-r--r--setuptools/__init__.py22
-rwxr-xr-xsetuptools/command/egg_info.py14
-rw-r--r--setuptools/dist.py296
-rw-r--r--setuptools/extension.py10
7 files changed, 356 insertions, 147 deletions
diff --git a/setup.py b/setup.py
index 7302f710..e56e15f9 100755
--- a/setup.py
+++ b/setup.py
@@ -46,8 +46,18 @@ setup(
"%(cmd)s = setuptools.command.%(cmd)s:%(cmd)s" % locals()
for cmd in SETUP_COMMANDS if cmd!="build_py" or sys.version<"2.4"
],
+ "distutils.setup_keywords": [
+ "eager_resources = setuptools.dist:assert_string_list",
+ "namespace_packages = setuptools.dist:check_nsp",
+ "extras_require = setuptools.dist:check_extras",
+ "entry_points = setuptools.dist:check_entry_points",
+ "test_suite = setuptools.dist:check_test_suite",
+ "zip_safe = setuptools.dist:assert_bool",
+ ]
},
+ setup_requires = ['setuptools>=0.6a0'],
+
classifiers = [f.strip() for f in """
Development Status :: 3 - Alpha
Intended Audience :: Developers
@@ -78,5 +88,3 @@ setup(
-
-
diff --git a/setuptools.egg-info/entry_points.txt b/setuptools.egg-info/entry_points.txt
index 8baf6137..def14fac 100755
--- a/setuptools.egg-info/entry_points.txt
+++ b/setuptools.egg-info/entry_points.txt
@@ -1,13 +1,22 @@
+[distutils.setup_keywords]
+entry_points = setuptools.dist:check_entry_points
+extras_require = setuptools.dist:check_extras
+namespace_packages = setuptools.dist:check_nsp
+test_suite = setuptools.dist:check_test_suite
+eager_resources = setuptools.dist:assert_string_list
+zip_safe = setuptools.dist:assert_bool
+
[distutils.commands]
rotate = setuptools.command.rotate:rotate
develop = setuptools.command.develop:develop
setopt = setuptools.command.setopt:setopt
+build_py = setuptools.command.build_py:build_py
saveopts = setuptools.command.saveopts:saveopts
egg_info = setuptools.command.egg_info:egg_info
-depends = setuptools.command.depends:depends
+easy_install = setuptools.command.easy_install:easy_install
upload = setuptools.command.upload:upload
alias = setuptools.command.alias:alias
-easy_install = setuptools.command.easy_install:easy_install
+depends = setuptools.command.depends:depends
bdist_egg = setuptools.command.bdist_egg:bdist_egg
install = setuptools.command.install:install
test = setuptools.command.test:test
diff --git a/setuptools.txt b/setuptools.txt
index 2bd40905..7f9c8551 100755
--- a/setuptools.txt
+++ b/setuptools.txt
@@ -64,7 +64,11 @@ Installing ``setuptools``
=========================
Download `ez_setup.py`_ and run it; this will download and install the
-appropriate egg for your Python version.
+appropriate egg for your Python version. (Note: if you are behind
+an NTLM-based firewall that prevents Python programs from accessing the net
+directly, you may wish to install and use the `APS proxy server
+<http://ntlmaps.sf.net/>`_, which lets you get past such firewalls in the same
+way that your web browser(s) do.)
.. _ez_setup.py: `bootstrap module`_
@@ -80,6 +84,16 @@ To get the in-development version of setuptools, run::
You can then install it using the usual "setup.py install" incantation.
+Note that ``setuptools`` *must* be installed as an egg directory; it will not
+operate correctly otherwise. If you are unable to install to a valid
+``site-packages`` directory (e.g. a "non-root install"), you will therefore
+need to manually add the setuptools egg to your ``PYTHONPATH``. (You won't
+need to do this for every egg you install, because the ``pkg_resources`` module
+can automatically find eggs and add them to ``sys.path`` at runtime. It's just
+that the ``setuptools`` egg contains ``pkg_resources`` and therefore has to
+be manually bootstrapped if you can't install it to a ``site-packages``
+directory.)
+
Basic Use
=========
@@ -175,6 +189,15 @@ unless you need the associated ``setuptools`` feature.
installed to support those features. See the section below on `Declaring
Dependencies`_ for details and examples of the format of this argument.
+``setup_requires``
+ A string or list of strings specifying what other distributions need to
+ be present in order for the *setup script* to run. ``setuptools`` will
+ attempt to obtain these (even going so far as to download them using
+ ``EasyInstall``) before processing the rest of the setup script or commands.
+ This argument is needed if you are using distutils extensions as part of
+ your build process; for example, extensions that process setup() arguments
+ and turn them into EGG-INFO metadata files.
+
``namespace_packages``
A list of strings naming the project's "namespace packages". A namespace
package is a package that may be split across multiple project
@@ -1517,19 +1540,28 @@ The ``upload`` command has a few options worth noting:
Extending and Reusing ``setuptools``
------------------------------------
-Sorry, this section isn't written yet, and neither is a lot of what's below
-this point, except for the change log. You might want to `subscribe to changes
-in this page <setuptools?action=subscribe>`_ to see when new documentation is
-added or updated.
+Creating ``distutils`` Extensions
+=================================
+
+It can be hard to add new commands or setup arguments to the distutils. But
+the ``setuptools`` package makes it a bit easier, by allowing you to distribute
+a distutils extension as a separate project, and then have projects that need
+the extension just refer to it in their ``setup_requires`` argument.
+
+With ``setuptools``, your distutils extension projects can hook in new
+commands and ``setup()`` arguments just by defining "entry points". These
+are mappings from command or argument names to a specification of where to
+import a handler from. (See the section on `Dynamic Discovery of Services and
+Plugins`_ above for some more background on entry points.)
Adding Commands
-===============
+---------------
-You can create add-on packages that extend setuptools with additional commands
-by defining entry points in the ``distutils.commands`` group. For example, if
-you wanted to add a ``foo`` command, you might add something like this to your
-setup script::
+You can add new ``setup`` commands by defining entry points in the
+``distutils.commands`` group. For example, if you wanted to add a ``foo``
+command, you might add something like this to your distutils extension
+project's setup script::
setup(
# ...
@@ -1540,8 +1572,8 @@ setup script::
},
)
-Assuming, of course, that the ``foo`` class in ``mypackage.some_module`` is
-a ``setuptools.Command`` subclass.
+(Assuming, of course, that the ``foo`` class in ``mypackage.some_module`` is
+a ``setuptools.Command`` subclass.)
Once a project containing such entry points has been activated on ``sys.path``,
(e.g. by running "install" or "develop" with a site-packages installation
@@ -1550,18 +1582,76 @@ scripts. It is not necessary to use the ``--command-packages`` option or
to monkeypatch the ``distutils.command`` package to install your commands;
``setuptools`` automatically adds a wrapper to the distutils to search for
entry points in the active distributions on ``sys.path``. In fact, this is
-how setuptools' own commands are installed: the setuptools setup script defines
-entry points for them.
+how setuptools' own commands are installed: the setuptools project's setup
+script defines entry points for them!
+
+
+Adding ``setup()`` Arguments
+----------------------------
+
+Sometimes, your commands may need additional arguments to the ``setup()``
+script. You can enable this by defining entry points in the
+``distutils.setup_keywords`` group. For example, if you wanted a ``setup()``
+argument called ``bar_baz``, you might add something like this to your
+distutils extension project's setup script::
+
+ setup(
+ # ...
+ entry_points = {
+ "distutils.commands": [
+ "foo = mypackage.some_module:foo",
+ ],
+ "distutils.setup_keywords": [
+ "bar_baz = mypackage.some_module:validate_bar_baz",
+ ],
+ },
+ )
+
+The idea here is that the entry point defines a function that will be called
+to validate the ``setup()`` argument, if it's supplied. The ``Distribution``
+object will have the initial value of the attribute set to ``None``, and the
+validation function will only be called if the ``setup()`` call sets it to
+a non-None value. Here's an example validation function::
+
+ def assert_bool(dist, attr, value):
+ """Verify that value is True, False, 0, or 1"""
+ if bool(value) != value:
+ raise DistutilsSetupError(
+ "%r must be a boolean value (got %r)" % (attr,value)
+ )
+
+Your function should accept three arguments: the ``Distribution`` object,
+the attribute name, and the attribute value. It should raise a
+``DistutilsSetupError`` (from the ``distutils.error`` module) if the argument
+is invalid. Remember, your function will only be called with non-None values,
+and the default value of arguments defined this way is always None. So, your
+commands should always be prepared for the possibility that the attribute will
+be ``None`` when they access it later.
+
+If more than one active distribution defines an entry point for the same
+``setup()`` argument, *all* of them will be called. This allows multiple
+distutils extensions to define a common argument, as long as they agree on
+what values of that argument are valid.
+
+Also note that as with commands, it is not necessary to subclass or monkeypatch
+the distutils ``Distribution`` class in order to add your arguments; it is
+sufficient to define the entry points in your extension, as long as the setup
+script lists your extension in its ``setup_requires`` argument.
Subclassing ``Command``
-----------------------
+Sorry, this section isn't written yet, and neither is a lot of what's below
+this point, except for the change log. You might want to `subscribe to changes
+in this page <setuptools?action=subscribe>`_ to see when new documentation is
+added or updated.
+
XXX
-Utility Modules
-===============
+Reusing ``setuptools`` Code
+===========================
``ez_setup``
------------
@@ -1604,14 +1694,24 @@ Release Notes/Change History
* The ``sdist`` command now recognizes Subversion "deleted file" entries and
does not include them in source distributions.
-
+
+ * ``setuptools`` now embeds itself more thoroughly into the distutils, so that
+ other distutils extensions (e.g. py2exe, py2app) will subclass setuptools'
+ versions of things, rather than the native distutils ones.
+
* Fixed some problems using ``pkg_resources`` w/PEP 302 loaders other than
``zipimport``, and the previously-broken "eager resource" support.
* Fixed ``pkg_resources.resource_exists()`` not working correctly, along with
some other resource API bugs.
- * Added ``entry_points`` argument to ``setup()``
+ * Added ``entry_points`` and ``setup_requires`` arguments to ``setup()``;
+ ``setup_requires`` allows you to automatically find and download packages
+ that are needed in order to *build* your project (as opposed to running it).
+
+ * ``setuptools`` now finds its commands and ``setup()`` argument validators
+ using entry points, so that they are extensible by third-party packages.
+ See `Creating distutils Extensions`_ above for more details.
* Many ``pkg_resources`` API changes and enhancements:
diff --git a/setuptools/__init__.py b/setuptools/__init__.py
index 05c4a73e..eeb2975b 100644
--- a/setuptools/__init__.py
+++ b/setuptools/__init__.py
@@ -1,6 +1,6 @@
"""Extensions to the 'distutils' for large or complex distributions"""
+from setuptools.dist import Distribution, Feature, _get_unpatched
import distutils.core, setuptools.command
-from setuptools.dist import Distribution, Feature
from setuptools.extension import Extension
from setuptools.depends import Require
from distutils.core import Command as _Command
@@ -39,17 +39,9 @@ def find_packages(where='.', exclude=()):
out = [item for item in out if not fnmatchcase(item,pat)]
return out
-def setup(**attrs):
- """Do package setup
-
- This function takes the same arguments as 'distutils.core.setup()', except
- that the default distribution class is 'setuptools.dist.Distribution'. See
- that class' documentation for details on the new keyword arguments that it
- makes available via this function.
- """
- attrs.setdefault("distclass",Distribution)
- return distutils.core.setup(**attrs)
+setup = distutils.core.setup
+_Command = _get_unpatched(_Command)
class Command(_Command):
__doc__ = _Command.__doc__
@@ -68,6 +60,14 @@ class Command(_Command):
setattr(cmd,k,v) # update command with keywords
return cmd
+import distutils.core
+distutils.core.Command = Command # we can't patch distutils.cmd, alas
+
+
+
+
+
+
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index 8577230f..7d0a1473 100755
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -9,7 +9,6 @@ from distutils.errors import *
from distutils import log
from pkg_resources import parse_requirements, safe_name, \
safe_version, yield_lines, EntryPoint
-from setuptools.dist import iter_distribution_names
class egg_info(Command):
@@ -39,6 +38,7 @@ class egg_info(Command):
+
def finalize_options (self):
self.egg_name = safe_name(self.distribution.get_name())
self.egg_version = self.tagged_version()
@@ -149,7 +149,7 @@ class egg_info(Command):
def write_toplevel_names(self):
pkgs = dict.fromkeys(
[k.split('.',1)[0]
- for k in iter_distribution_names(self.distribution)
+ for k in self.distribution.iter_distribution_names()
]
)
toplevel = os.path.join(self.egg_info, "top_level.txt")
@@ -164,12 +164,8 @@ class egg_info(Command):
def write_or_delete_dist_arg(self, argname, filename=None):
value = getattr(self.distribution, argname, None)
- if value is None:
- return
-
filename = filename or argname+'.txt'
filename = os.path.join(self.egg_info,filename)
-
if value:
log.info("writing %s", filename)
if not self.dry_run:
@@ -177,8 +173,12 @@ class egg_info(Command):
f.write('\n'.join(value))
f.write('\n')
f.close()
-
elif os.path.exists(filename):
+ if value is None:
+ log.warn(
+ "%s not set in setup(), but %s exists", argname, filename
+ )
+ return
log.info("deleting %s", filename)
if not self.dry_run:
os.unlink(filename)
diff --git a/setuptools/dist.py b/setuptools/dist.py
index 40234b4e..6d226d68 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -9,36 +9,118 @@ from setuptools.command.sdist import sdist
from setuptools.command.install_lib import install_lib
from distutils.errors import DistutilsOptionError, DistutilsPlatformError
from distutils.errors import DistutilsSetupError
-import setuptools, pkg_resources
-
-def get_command_class(self, command):
- """Pluggable version of get_command_class()"""
- if command in self.cmdclass:
- return self.cmdclass[command]
-
- for ep in pkg_resources.iter_entry_points('distutils.commands',command):
- self.cmdclass[command] = cmdclass = ep.load()
- return cmdclass
- else:
- return _old_get_command_class(self, command)
-
-def print_commands(self):
- for ep in pkg_resources.iter_entry_points('distutils.commands'):
- if ep.name not in self.cmdclass:
- cmdclass = ep.load(False) # don't require extras, we're not running
- self.cmdclass[ep.name] = cmdclass
- return _old_print_commands(self)
-
-for meth in 'print_commands', 'get_command_class':
- if getattr(_Distribution,meth).im_func.func_globals is not globals():
- globals()['_old_'+meth] = getattr(_Distribution,meth)
- setattr(_Distribution, meth, globals()[meth])
+import setuptools, pkg_resources, distutils.core, distutils.dist, distutils.cmd
+import os
+
+def _get_unpatched(cls):
+ """Protect against re-patching the distutils if reloaded
+
+ Also ensures that no other distutils extension monkeypatched the distutils
+ first.
+ """
+ while cls.__module__.startswith('setuptools'):
+ cls, = cls.__bases__
+ if not cls.__module__.startswith('distutils'):
+ raise AssertionError(
+ "distutils has already been patched by %r" % cls
+ )
+ return cls
+
+_Distribution = _get_unpatched(_Distribution)
sequence = tuple, list
+
+
+
+
+
+
+def assert_string_list(dist, attr, value):
+ """Verify that value is a string list or None"""
+ try:
+ assert ''.join(value)!=value
+ except (TypeError,ValueError,AttributeError,AssertionError):
+ raise DistutilsSetupError(
+ "%r must be a list of strings (got %r)" % (attr,value)
+ )
+
+def check_nsp(dist, attr, value):
+ """Verify that namespace packages are valid"""
+ assert_string_list(dist,attr,value)
+
+ for nsp in value:
+ for name in dist.iter_distribution_names():
+ if name.startswith(nsp+'.'): break
+ else:
+ raise DistutilsSetupError(
+ "Distribution contains no modules or packages for " +
+ "namespace package %r" % nsp
+ )
+
+def check_extras(dist, attr, value):
+ """Verify that extras_require mapping is valid"""
+ try:
+ for k,v in value.items():
+ list(pkg_resources.parse_requirements(v))
+ except (TypeError,ValueError,AttributeError):
+ raise DistutilsSetupError(
+ "'extras_require' must be a dictionary whose values are "
+ "strings or lists of strings containing valid project/version "
+ "requirement specifiers."
+ )
+
+def assert_bool(dist, attr, value):
+ """Verify that value is True, False, 0, or 1"""
+ if bool(value) != value:
+ raise DistutilsSetupError(
+ "%r must be a boolean value (got %r)" % (attr,value)
+ )
+
+def check_install_requires(dist, attr, value):
+ """Verify that install_requires is a valid requirements list"""
+ try:
+ list(pkg_resources.parse_requirements(value))
+ except (TypeError,ValueError):
+ raise DistutilsSetupError(
+ "'install_requires' must be a string or list of strings "
+ "containing valid project/version requirement specifiers"
+ )
+
+def check_entry_points(dist, attr, value):
+ """Verify that entry_points map is parseable"""
+ try:
+ pkg_resources.EntryPoint.parse_map(value)
+ except ValueError, e:
+ raise DistutilsSetupError(e)
+
+
+def check_test_suite(dist, attr, value):
+ if not isinstance(value,basestring):
+ raise DistutilsSetupError("test_suite must be a string")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
class Distribution(_Distribution):
"""Distribution with support for features, tests, and package data
@@ -125,16 +207,19 @@ class Distribution(_Distribution):
have_package_data = hasattr(self, "package_data")
if not have_package_data:
self.package_data = {}
+
self.features = {}
- self.test_suite = None
self.requires = []
- self.install_requires = []
- self.extras_require = {}
self.dist_files = []
- self.zip_safe = None
- self.namespace_packages = None
- self.eager_resources = None
- self.entry_points = None
+
+ if attrs and 'setup_requires' in attrs:
+ # Make sure we have any eggs needed to interpret 'attrs'
+ self.fetch_build_eggs(attrs.pop('setup_requires'))
+
+ for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
+ if not hasattr(self,ep.name):
+ setattr(self,ep.name,None)
+
_Distribution.__init__(self,attrs)
@@ -145,20 +230,17 @@ class Distribution(_Distribution):
self._finalize_features()
return result
-
def _feature_attrname(self,name):
"""Convert feature name to corresponding option attribute name"""
return 'with_'+name.replace('-','_')
-
-
-
-
-
-
-
-
-
+ def fetch_build_eggs(self, requires):
+ """Resolve pre-setup requirements"""
+ from pkg_resources import working_set, parse_requirements
+ for dist in working_set.resolve(
+ parse_requirements(requires), installer=self.fetch_build_egg
+ ):
+ working_set.add(dist)
@@ -174,49 +256,34 @@ class Distribution(_Distribution):
"setuptools. Please remove it from your setup script."
)
- try:
- list(pkg_resources.parse_requirements(self.install_requires))
- except (TypeError,ValueError):
- raise DistutilsSetupError(
- "'install_requires' must be a string or list of strings "
- "containing valid project/version requirement specifiers"
- )
+ for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
+ value = getattr(self,ep.name,None)
+ if value is not None:
+ ep.require(installer=self.fetch_build_egg)
+ ep.load()(self, ep.name, value)
+
+ def fetch_build_egg(self, req):
+ """Fetch an egg needed for building"""
try:
- for k,v in self.extras_require.items():
- list(pkg_resources.parse_requirements(v))
- except (TypeError,ValueError,AttributeError):
- raise DistutilsSetupError(
- "'extras_require' must be a dictionary whose values are "
- "strings or lists of strings containing valid project/version "
- "requirement specifiers."
+ cmd = self._egg_fetcher
+ except AttributeError:
+ from setuptools.command.easy_install import easy_install
+ cmd = easy_install(
+ self.__class__({'script_args':['easy_install']}),
+ args="x", install_dir=os.curdir, exclude_scripts=True,
+ always_copy=False, build_directory=None, editable=False,
+ upgrade=False
)
+ cmd.ensure_finalized()
+ cmd.zip_ok = None # override any setup.cfg setting for these
+ cmd.build_directory = None
+ self._egg_fetcher = cmd
- for attr in 'namespace_packages','eager_resources':
- value = getattr(self,attr,None)
- if value is not None:
- try:
- assert ''.join(value)!=value
- except (TypeError,ValueError,AttributeError,AssertionError):
- raise DistutilsSetupError(
- "%r must be a list of strings (got %r)" % (attr,value)
- )
+ return cmd.easy_install(req)
- for nsp in self.namespace_packages or ():
- for name in iter_distribution_names(self):
- if name.startswith(nsp+'.'): break
- else:
- raise DistutilsSetupError(
- "Distribution contains no modules or packages for " +
- "namespace package %r" % nsp
- )
- if self.entry_points is not None:
- try:
- pkg_resources.EntryPoint.parse_map(self.entry_points)
- except ValueError, e:
- raise DistutilsSetupError(e)
def _set_global_opts_from_features(self):
"""Add --with-X/--without-X options based on optional features"""
@@ -244,22 +311,7 @@ class Distribution(_Distribution):
- def _finalize_features(self):
- """Add/remove features and resolve dependencies between them"""
-
- # First, flag all the enabled items (and thus their dependencies)
- for name,feature in self.features.items():
- enabled = self.feature_is_included(name)
- if enabled or (enabled is None and feature.include_by_default()):
- feature.include_in(self)
- self._set_feature(name,1)
- # Then disable the rest, so that off-by-default features don't
- # get flagged as errors when they're required by an enabled feature
- for name,feature in self.features.items():
- if not self.feature_is_included(name):
- feature.exclude_from(self)
- self._set_feature(name,0)
@@ -274,12 +326,42 @@ class Distribution(_Distribution):
+ def _finalize_features(self):
+ """Add/remove features and resolve dependencies between them"""
+ # First, flag all the enabled items (and thus their dependencies)
+ for name,feature in self.features.items():
+ enabled = self.feature_is_included(name)
+ if enabled or (enabled is None and feature.include_by_default()):
+ feature.include_in(self)
+ self._set_feature(name,1)
+ # Then disable the rest, so that off-by-default features don't
+ # get flagged as errors when they're required by an enabled feature
+ for name,feature in self.features.items():
+ if not self.feature_is_included(name):
+ feature.exclude_from(self)
+ self._set_feature(name,0)
+ def get_command_class(self, command):
+ """Pluggable version of get_command_class()"""
+ if command in self.cmdclass:
+ return self.cmdclass[command]
+ for ep in pkg_resources.iter_entry_points('distutils.commands',command):
+ ep.require(installer=self.fetch_build_egg)
+ self.cmdclass[command] = cmdclass = ep.load()
+ return cmdclass
+ else:
+ return _Distribution.get_command_class(self, command)
+ def print_commands(self):
+ for ep in pkg_resources.iter_entry_points('distutils.commands'):
+ if ep.name not in self.cmdclass:
+ cmdclass = ep.load(False) # don't require extras, we're not running
+ self.cmdclass[ep.name] = cmdclass
+ return _Distribution.print_commands(self)
@@ -572,25 +654,25 @@ class Distribution(_Distribution):
return d
-def iter_distribution_names(distribution):
- """Yield all packages, modules, and extensions declared by distribution"""
-
- for pkg in distribution.packages or ():
- yield pkg
-
- for module in distribution.py_modules or ():
- yield module
-
- for ext in distribution.ext_modules or ():
- if isinstance(ext,tuple):
- name,buildinfo = ext
- yield name
- else:
- yield ext.name
+ def iter_distribution_names(self):
+ """Yield all packages, modules, and extension names in distribution"""
+ for pkg in self.packages or ():
+ yield pkg
+ for module in self.py_modules or ():
+ yield module
+ for ext in self.ext_modules or ():
+ if isinstance(ext,tuple):
+ name,buildinfo = ext
+ yield name
+ else:
+ yield ext.name
+# Install it throughout the distutils
+for module in distutils.dist, distutils.core, distutils.cmd:
+ module.Distribution = Distribution
diff --git a/setuptools/extension.py b/setuptools/extension.py
index 55a4d946..37b62576 100644
--- a/setuptools/extension.py
+++ b/setuptools/extension.py
@@ -7,6 +7,9 @@ except ImportError:
# Pyrex isn't around, so fix up the sources
+ from dist import _get_unpatched
+ _Extension = _get_unpatched(_Extension)
+
class Extension(_Extension):
"""Extension that uses '.c' files in place of '.pyx' files"""
@@ -21,7 +24,14 @@ except ImportError:
sources.append(s)
self.sources = sources
+ import sys, distutils.core, distutils.extension
+ distutils.core.Extension = Extension
+ distutils.extension.Extension = Extension
+ if 'distutils.command.build_ext' in sys.modules:
+ sys.modules['distutils.command.build_ext'].Extension = Extension
+
else:
# Pyrex is here, just use regular extension type
Extension = _Extension
+