Skip to content

Commit c719690

Browse files
committed
Remove the Features feature. Fixes #65.
This commit reverts e4460fa.
1 parent c389dd1 commit c719690

File tree

4 files changed

+7
-344
lines changed

4 files changed

+7
-344
lines changed

setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ def pypi_link(pkg_filename):
9191
],
9292
"setuptools.finalize_distribution_options": [
9393
"parent_finalize = setuptools.dist:_Distribution.finalize_options",
94-
"features = setuptools.dist:Distribution._finalize_feature_opts",
9594
"keywords = setuptools.dist:Distribution._finalize_setup_keywords",
9695
"2to3_doctests = "
9796
"setuptools.dist:Distribution._finalize_2to3_doctests",

setuptools/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Extensions to the 'distutils' for large or complex distributions"""
22

33
import os
4-
import sys
54
import functools
65
import distutils.core
76
import distutils.filelist
@@ -17,21 +16,21 @@
1716

1817
import setuptools.version
1918
from setuptools.extension import Extension
20-
from setuptools.dist import Distribution, Feature
19+
from setuptools.dist import Distribution
2120
from setuptools.depends import Require
2221
from . import monkey
2322

2423
__metaclass__ = type
2524

2625

2726
__all__ = [
28-
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
27+
'setup', 'Distribution', 'Command', 'Extension', 'Require',
2928
'SetuptoolsDeprecationWarning',
3029
'find_packages'
3130
]
3231

3332
if PY3:
34-
__all__.append('find_namespace_packages')
33+
__all__.append('find_namespace_packages')
3534

3635
__version__ = setuptools.version.__version__
3736

setuptools/dist.py

Lines changed: 3 additions & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
from collections import defaultdict
2020
from email import message_from_file
2121

22-
from distutils.errors import (
23-
DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError,
24-
)
22+
from distutils.errors import DistutilsOptionError, DistutilsSetupError
2523
from distutils.util import rfc822_escape
2624
from distutils.version import StrictVersion
2725

@@ -32,7 +30,6 @@
3230

3331
from . import SetuptoolsDeprecationWarning
3432

35-
from setuptools.depends import Require
3633
from setuptools import windows_support
3734
from setuptools.monkey import get_unpatched
3835
from setuptools.config import parse_configuration
@@ -338,7 +335,7 @@ def check_packages(dist, attr, value):
338335

339336

340337
class Distribution(_Distribution):
341-
"""Distribution with support for features, tests, and package data
338+
"""Distribution with support for tests and package data
342339
343340
This is an enhanced version of 'distutils.dist.Distribution' that
344341
effectively adds the following new optional keyword arguments to 'setup()':
@@ -365,21 +362,6 @@ class Distribution(_Distribution):
365362
EasyInstall and requests one of your extras, the corresponding
366363
additional requirements will be installed if needed.
367364
368-
'features' **deprecated** -- a dictionary mapping option names to
369-
'setuptools.Feature'
370-
objects. Features are a portion of the distribution that can be
371-
included or excluded based on user options, inter-feature dependencies,
372-
and availability on the current system. Excluded features are omitted
373-
from all setup commands, including source and binary distributions, so
374-
you can create multiple distributions from the same source tree.
375-
Feature names should be valid Python identifiers, except that they may
376-
contain the '-' (minus) sign. Features can be included or excluded
377-
via the command line options '--with-X' and '--without-X', where 'X' is
378-
the name of the feature. Whether a feature is included by default, and
379-
whether you are allowed to control this from the command line, is
380-
determined by the Feature object. See the 'Feature' class for more
381-
information.
382-
383365
'test_suite' -- the name of a test suite to run for the 'test' command.
384366
If the user runs 'python setup.py test', the package will be installed,
385367
and the named test suite will be run. The format is the same as
@@ -401,8 +383,7 @@ class Distribution(_Distribution):
401383
for manipulating the distribution's contents. For example, the 'include()'
402384
and 'exclude()' methods can be thought of as in-place add and subtract
403385
commands that add or remove packages, modules, extensions, and so on from
404-
the distribution. They are used by the feature subsystem to configure the
405-
distribution for the included and excluded features.
386+
the distribution.
406387
"""
407388

408389
_DISTUTILS_UNSUPPORTED_METADATA = {
@@ -432,10 +413,6 @@ def __init__(self, attrs=None):
432413
if not have_package_data:
433414
self.package_data = {}
434415
attrs = attrs or {}
435-
if 'features' in attrs or 'require_features' in attrs:
436-
Feature.warn_deprecated()
437-
self.require_features = []
438-
self.features = {}
439416
self.dist_files = []
440417
# Filter-out setuptools' specific options.
441418
self.src_root = attrs.pop("src_root", None)
@@ -702,17 +679,6 @@ def parse_config_files(self, filenames=None, ignore_option_errors=False):
702679
ignore_option_errors=ignore_option_errors)
703680
self._finalize_requires()
704681

705-
def parse_command_line(self):
706-
"""Process features after parsing command line options"""
707-
result = _Distribution.parse_command_line(self)
708-
if self.features:
709-
self._finalize_features()
710-
return result
711-
712-
def _feature_attrname(self, name):
713-
"""Convert feature name to corresponding option attribute name"""
714-
return 'with_' + name.replace('-', '_')
715-
716682
def fetch_build_eggs(self, requires):
717683
"""Resolve pre-setup requirements"""
718684
resolved_dists = pkg_resources.working_set.resolve(
@@ -776,53 +742,6 @@ def fetch_build_egg(self, req):
776742
from setuptools.installer import fetch_build_egg
777743
return fetch_build_egg(self, req)
778744

779-
def _finalize_feature_opts(self):
780-
"""Add --with-X/--without-X options based on optional features"""
781-
782-
if not self.features:
783-
return
784-
785-
go = []
786-
no = self.negative_opt.copy()
787-
788-
for name, feature in self.features.items():
789-
self._set_feature(name, None)
790-
feature.validate(self)
791-
792-
if feature.optional:
793-
descr = feature.description
794-
incdef = ' (default)'
795-
excdef = ''
796-
if not feature.include_by_default():
797-
excdef, incdef = incdef, excdef
798-
799-
new = (
800-
('with-' + name, None, 'include ' + descr + incdef),
801-
('without-' + name, None, 'exclude ' + descr + excdef),
802-
)
803-
go.extend(new)
804-
no['without-' + name] = 'with-' + name
805-
806-
self.global_options = self.feature_options = go + self.global_options
807-
self.negative_opt = self.feature_negopt = no
808-
809-
def _finalize_features(self):
810-
"""Add/remove features and resolve dependencies between them"""
811-
812-
# First, flag all the enabled items (and thus their dependencies)
813-
for name, feature in self.features.items():
814-
enabled = self.feature_is_included(name)
815-
if enabled or (enabled is None and feature.include_by_default()):
816-
feature.include_in(self)
817-
self._set_feature(name, 1)
818-
819-
# Then disable the rest, so that off-by-default features don't
820-
# get flagged as errors when they're required by an enabled feature
821-
for name, feature in self.features.items():
822-
if not self.feature_is_included(name):
823-
feature.exclude_from(self)
824-
self._set_feature(name, 0)
825-
826745
def get_command_class(self, command):
827746
"""Pluggable version of get_command_class()"""
828747
if command in self.cmdclass:
@@ -852,25 +771,6 @@ def get_command_list(self):
852771
self.cmdclass[ep.name] = cmdclass
853772
return _Distribution.get_command_list(self)
854773

855-
def _set_feature(self, name, status):
856-
"""Set feature's inclusion status"""
857-
setattr(self, self._feature_attrname(name), status)
858-
859-
def feature_is_included(self, name):
860-
"""Return 1 if feature is included, 0 if excluded, 'None' if unknown"""
861-
return getattr(self, self._feature_attrname(name))
862-
863-
def include_feature(self, name):
864-
"""Request inclusion of feature named 'name'"""
865-
866-
if self.feature_is_included(name) == 0:
867-
descr = self.features[name].description
868-
raise DistutilsOptionError(
869-
descr + " is required, but was excluded or is not available"
870-
)
871-
self.features[name].include_in(self)
872-
self._set_feature(name, 1)
873-
874774
def include(self, **attrs):
875775
"""Add items to distribution that are named in keyword arguments
876776
@@ -1115,160 +1015,6 @@ def handle_display_options(self, option_order):
11151015
sys.stdout.detach(), encoding, errors, newline, line_buffering)
11161016

11171017

1118-
class Feature:
1119-
"""
1120-
**deprecated** -- The `Feature` facility was never completely implemented
1121-
or supported, `has reported issues
1122-
<https://github.com/pypa/setuptools/issues/58>`_ and will be removed in
1123-
a future version.
1124-
1125-
A subset of the distribution that can be excluded if unneeded/wanted
1126-
1127-
Features are created using these keyword arguments:
1128-
1129-
'description' -- a short, human readable description of the feature, to
1130-
be used in error messages, and option help messages.
1131-
1132-
'standard' -- if true, the feature is included by default if it is
1133-
available on the current system. Otherwise, the feature is only
1134-
included if requested via a command line '--with-X' option, or if
1135-
another included feature requires it. The default setting is 'False'.
1136-
1137-
'available' -- if true, the feature is available for installation on the
1138-
current system. The default setting is 'True'.
1139-
1140-
'optional' -- if true, the feature's inclusion can be controlled from the
1141-
command line, using the '--with-X' or '--without-X' options. If
1142-
false, the feature's inclusion status is determined automatically,
1143-
based on 'availabile', 'standard', and whether any other feature
1144-
requires it. The default setting is 'True'.
1145-
1146-
'require_features' -- a string or sequence of strings naming features
1147-
that should also be included if this feature is included. Defaults to
1148-
empty list. May also contain 'Require' objects that should be
1149-
added/removed from the distribution.
1150-
1151-
'remove' -- a string or list of strings naming packages to be removed
1152-
from the distribution if this feature is *not* included. If the
1153-
feature *is* included, this argument is ignored. This argument exists
1154-
to support removing features that "crosscut" a distribution, such as
1155-
defining a 'tests' feature that removes all the 'tests' subpackages
1156-
provided by other features. The default for this argument is an empty
1157-
list. (Note: the named package(s) or modules must exist in the base
1158-
distribution when the 'setup()' function is initially called.)
1159-
1160-
other keywords -- any other keyword arguments are saved, and passed to
1161-
the distribution's 'include()' and 'exclude()' methods when the
1162-
feature is included or excluded, respectively. So, for example, you
1163-
could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be
1164-
added or removed from the distribution as appropriate.
1165-
1166-
A feature must include at least one 'requires', 'remove', or other
1167-
keyword argument. Otherwise, it can't affect the distribution in any way.
1168-
Note also that you can subclass 'Feature' to create your own specialized
1169-
feature types that modify the distribution in other ways when included or
1170-
excluded. See the docstrings for the various methods here for more detail.
1171-
Aside from the methods, the only feature attributes that distributions look
1172-
at are 'description' and 'optional'.
1173-
"""
1174-
1175-
@staticmethod
1176-
def warn_deprecated():
1177-
msg = (
1178-
"Features are deprecated and will be removed in a future "
1179-
"version. See https://github.com/pypa/setuptools/issues/65."
1180-
)
1181-
warnings.warn(msg, DistDeprecationWarning, stacklevel=3)
1182-
1183-
def __init__(
1184-
self, description, standard=False, available=True,
1185-
optional=True, require_features=(), remove=(), **extras):
1186-
self.warn_deprecated()
1187-
1188-
self.description = description
1189-
self.standard = standard
1190-
self.available = available
1191-
self.optional = optional
1192-
if isinstance(require_features, (str, Require)):
1193-
require_features = require_features,
1194-
1195-
self.require_features = [
1196-
r for r in require_features if isinstance(r, str)
1197-
]
1198-
er = [r for r in require_features if not isinstance(r, str)]
1199-
if er:
1200-
extras['require_features'] = er
1201-
1202-
if isinstance(remove, str):
1203-
remove = remove,
1204-
self.remove = remove
1205-
self.extras = extras
1206-
1207-
if not remove and not require_features and not extras:
1208-
raise DistutilsSetupError(
1209-
"Feature %s: must define 'require_features', 'remove', or "
1210-
"at least one of 'packages', 'py_modules', etc."
1211-
)
1212-
1213-
def include_by_default(self):
1214-
"""Should this feature be included by default?"""
1215-
return self.available and self.standard
1216-
1217-
def include_in(self, dist):
1218-
"""Ensure feature and its requirements are included in distribution
1219-
1220-
You may override this in a subclass to perform additional operations on
1221-
the distribution. Note that this method may be called more than once
1222-
per feature, and so should be idempotent.
1223-
1224-
"""
1225-
1226-
if not self.available:
1227-
raise DistutilsPlatformError(
1228-
self.description + " is required, "
1229-
"but is not available on this platform"
1230-
)
1231-
1232-
dist.include(**self.extras)
1233-
1234-
for f in self.require_features:
1235-
dist.include_feature(f)
1236-
1237-
def exclude_from(self, dist):
1238-
"""Ensure feature is excluded from distribution
1239-
1240-
You may override this in a subclass to perform additional operations on
1241-
the distribution. This method will be called at most once per
1242-
feature, and only after all included features have been asked to
1243-
include themselves.
1244-
"""
1245-
1246-
dist.exclude(**self.extras)
1247-
1248-
if self.remove:
1249-
for item in self.remove:
1250-
dist.exclude_package(item)
1251-
1252-
def validate(self, dist):
1253-
"""Verify that feature makes sense in context of distribution
1254-
1255-
This method is called by the distribution just before it parses its
1256-
command line. It checks to ensure that the 'remove' attribute, if any,
1257-
contains only valid package/module names that are present in the base
1258-
distribution when 'setup()' is called. You may override it in a
1259-
subclass to perform any other required validation of the feature
1260-
against a target distribution.
1261-
"""
1262-
1263-
for item in self.remove:
1264-
if not dist.has_contents_for(item):
1265-
raise DistutilsSetupError(
1266-
"%s wants to be able to remove %s, but the distribution"
1267-
" doesn't contain any packages or modules under %s"
1268-
% (self.description, item, item)
1269-
)
1270-
1271-
12721018
class DistDeprecationWarning(SetuptoolsDeprecationWarning):
12731019
"""Class for warning about deprecations in dist in
12741020
setuptools. Not ignored by default, unlike DeprecationWarning."""

0 commit comments

Comments
 (0)