Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
setuptools
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jérome Perrin
setuptools
Commits
dfd59c2a
Commit
dfd59c2a
authored
Mar 08, 2020
by
Jason R. Coombs
Committed by
GitHub
Mar 08, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1979 from pypa/debt/remove-features
Remove Feature support
parents
37e1ca6d
da94b050
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
7 additions
and
342 deletions
+7
-342
changelog.d/65.breaking.rst
changelog.d/65.breaking.rst
+1
-0
setup.py
setup.py
+0
-1
setuptools/__init__.py
setuptools/__init__.py
+2
-2
setuptools/dist.py
setuptools/dist.py
+3
-257
setuptools/tests/test_setuptools.py
setuptools/tests/test_setuptools.py
+1
-82
No files found.
changelog.d/65.breaking.rst
0 → 100644
View file @
dfd59c2a
Once again as in 3.0, removed the Features feature.
setup.py
View file @
dfd59c2a
...
...
@@ -91,7 +91,6 @@ setup_params = dict(
],
"setuptools.finalize_distribution_options"
:
[
"parent_finalize = setuptools.dist:_Distribution.finalize_options"
,
"features = setuptools.dist:Distribution._finalize_feature_opts"
,
"keywords = setuptools.dist:Distribution._finalize_setup_keywords"
,
"2to3_doctests = "
"setuptools.dist:Distribution._finalize_2to3_doctests"
,
...
...
setuptools/__init__.py
View file @
dfd59c2a
...
...
@@ -16,7 +16,7 @@ from setuptools.extern.six.moves import filter, map
import
setuptools.version
from
setuptools.extension
import
Extension
from
setuptools.dist
import
Distribution
,
Feature
from
setuptools.dist
import
Distribution
from
setuptools.depends
import
Require
from
.
import
monkey
...
...
@@ -24,7 +24,7 @@ __metaclass__ = type
__all__
=
[
'setup'
,
'Distribution'
,
'
Feature'
,
'
Command'
,
'Extension'
,
'Require'
,
'setup'
,
'Distribution'
,
'Command'
,
'Extension'
,
'Require'
,
'SetuptoolsDeprecationWarning'
,
'find_packages'
]
...
...
setuptools/dist.py
View file @
dfd59c2a
...
...
@@ -19,9 +19,7 @@ import itertools
from
collections
import
defaultdict
from
email
import
message_from_file
from
distutils.errors
import
(
DistutilsOptionError
,
DistutilsPlatformError
,
DistutilsSetupError
,
)
from
distutils.errors
import
DistutilsOptionError
,
DistutilsSetupError
from
distutils.util
import
rfc822_escape
from
distutils.version
import
StrictVersion
...
...
@@ -32,7 +30,6 @@ from setuptools.extern.six.moves import map, filter, filterfalse
from
.
import
SetuptoolsDeprecationWarning
from
setuptools.depends
import
Require
from
setuptools
import
windows_support
from
setuptools.monkey
import
get_unpatched
from
setuptools.config
import
parse_configuration
...
...
@@ -338,7 +335,7 @@ _Distribution = get_unpatched(distutils.core.Distribution)
class Distribution(_Distribution):
"""Distribution with support for
features, tests,
and package data
"""Distribution with support for
tests
and package data
This is an enhanced version of '
distutils
.
dist
.
Distribution
' that
effectively adds the following new optional keyword arguments to '
setup
()
':
...
...
@@ -365,21 +362,6 @@ class Distribution(_Distribution):
EasyInstall
and
requests
one
of
your
extras
,
the
corresponding
additional
requirements
will
be
installed
if
needed
.
'features'
**
deprecated
**
--
a
dictionary
mapping
option
names
to
'setuptools.Feature'
objects
.
Features
are
a
portion
of
the
distribution
that
can
be
included
or
excluded
based
on
user
options
,
inter
-
feature
dependencies
,
and
availability
on
the
current
system
.
Excluded
features
are
omitted
from
all
setup
commands
,
including
source
and
binary
distributions
,
so
you
can
create
multiple
distributions
from
the
same
source
tree
.
Feature
names
should
be
valid
Python
identifiers
,
except
that
they
may
contain
the
'-'
(
minus
)
sign
.
Features
can
be
included
or
excluded
via
the
command
line
options
'--with-X'
and
'--without-X'
,
where
'X'
is
the
name
of
the
feature
.
Whether
a
feature
is
included
by
default
,
and
whether
you
are
allowed
to
control
this
from
the
command
line
,
is
determined
by
the
Feature
object
.
See
the
'Feature'
class
for
more
information
.
'test_suite'
--
the
name
of
a
test
suite
to
run
for
the
'test'
command
.
If
the
user
runs
'python setup.py test'
,
the
package
will
be
installed
,
and
the
named
test
suite
will
be
run
.
The
format
is
the
same
as
...
...
@@ -401,8 +383,7 @@ class Distribution(_Distribution):
for
manipulating
the
distribution
's contents. For example, the '
include
()
'
and '
exclude
()
' methods can be thought of as in-place add and subtract
commands that add or remove packages, modules, extensions, and so on from
the distribution. They are used by the feature subsystem to configure the
distribution for the included and excluded features.
the distribution.
"""
_DISTUTILS_UNSUPPORTED_METADATA = {
...
...
@@ -432,10 +413,6 @@ class Distribution(_Distribution):
if not have_package_data:
self.package_data = {}
attrs = attrs or {}
if '
features
' in attrs or '
require_features
' in attrs:
Feature.warn_deprecated()
self.require_features = []
self.features = {}
self.dist_files = []
# Filter-out setuptools'
specific
options
.
self
.
src_root
=
attrs
.
pop
(
"src_root"
,
None
)
...
...
@@ -702,17 +679,6 @@ class Distribution(_Distribution):
ignore_option_errors
=
ignore_option_errors
)
self
.
_finalize_requires
()
def
parse_command_line
(
self
):
"""Process features after parsing command line options"""
result
=
_Distribution
.
parse_command_line
(
self
)
if
self
.
features
:
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"""
resolved_dists
=
pkg_resources
.
working_set
.
resolve
(
...
...
@@ -776,53 +742,6 @@ class Distribution(_Distribution):
from
setuptools.installer
import
fetch_build_egg
return
fetch_build_egg
(
self
,
req
)
def
_finalize_feature_opts
(
self
):
"""Add --with-X/--without-X options based on optional features"""
if
not
self
.
features
:
return
go
=
[]
no
=
self
.
negative_opt
.
copy
()
for
name
,
feature
in
self
.
features
.
items
():
self
.
_set_feature
(
name
,
None
)
feature
.
validate
(
self
)
if
feature
.
optional
:
descr
=
feature
.
description
incdef
=
' (default)'
excdef
=
''
if
not
feature
.
include_by_default
():
excdef
,
incdef
=
incdef
,
excdef
new
=
(
(
'with-'
+
name
,
None
,
'include '
+
descr
+
incdef
),
(
'without-'
+
name
,
None
,
'exclude '
+
descr
+
excdef
),
)
go
.
extend
(
new
)
no
[
'without-'
+
name
]
=
'with-'
+
name
self
.
global_options
=
self
.
feature_options
=
go
+
self
.
global_options
self
.
negative_opt
=
self
.
feature_negopt
=
no
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
:
...
...
@@ -852,25 +771,6 @@ class Distribution(_Distribution):
self
.
cmdclass
[
ep
.
name
]
=
cmdclass
return
_Distribution
.
get_command_list
(
self
)
def
_set_feature
(
self
,
name
,
status
):
"""Set feature's inclusion status"""
setattr
(
self
,
self
.
_feature_attrname
(
name
),
status
)
def
feature_is_included
(
self
,
name
):
"""Return 1 if feature is included, 0 if excluded, 'None' if unknown"""
return
getattr
(
self
,
self
.
_feature_attrname
(
name
))
def
include_feature
(
self
,
name
):
"""Request inclusion of feature named 'name'"""
if
self
.
feature_is_included
(
name
)
==
0
:
descr
=
self
.
features
[
name
].
description
raise
DistutilsOptionError
(
descr
+
" is required, but was excluded or is not available"
)
self
.
features
[
name
].
include_in
(
self
)
self
.
_set_feature
(
name
,
1
)
def
include
(
self
,
**
attrs
):
"""Add items to distribution that are named in keyword arguments
...
...
@@ -1115,160 +1015,6 @@ class Distribution(_Distribution):
sys
.
stdout
.
detach
(),
encoding
,
errors
,
newline
,
line_buffering
)
class
Feature
:
"""
**deprecated** -- The `Feature` facility was never completely implemented
or supported, `has reported issues
<https://github.com/pypa/setuptools/issues/58>`_ and will be removed in
a future version.
A subset of the distribution that can be excluded if unneeded/wanted
Features are created using these keyword arguments:
'description' -- a short, human readable description of the feature, to
be used in error messages, and option help messages.
'standard' -- if true, the feature is included by default if it is
available on the current system. Otherwise, the feature is only
included if requested via a command line '--with-X' option, or if
another included feature requires it. The default setting is 'False'.
'available' -- if true, the feature is available for installation on the
current system. The default setting is 'True'.
'optional' -- if true, the feature's inclusion can be controlled from the
command line, using the '--with-X' or '--without-X' options. If
false, the feature's inclusion status is determined automatically,
based on 'availabile', 'standard', and whether any other feature
requires it. The default setting is 'True'.
'require_features' -- a string or sequence of strings naming features
that should also be included if this feature is included. Defaults to
empty list. May also contain 'Require' objects that should be
added/removed from the distribution.
'remove' -- a string or list of strings naming packages to be removed
from the distribution if this feature is *not* included. If the
feature *is* included, this argument is ignored. This argument exists
to support removing features that "crosscut" a distribution, such as
defining a 'tests' feature that removes all the 'tests' subpackages
provided by other features. The default for this argument is an empty
list. (Note: the named package(s) or modules must exist in the base
distribution when the 'setup()' function is initially called.)
other keywords -- any other keyword arguments are saved, and passed to
the distribution's 'include()' and 'exclude()' methods when the
feature is included or excluded, respectively. So, for example, you
could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be
added or removed from the distribution as appropriate.
A feature must include at least one 'requires', 'remove', or other
keyword argument. Otherwise, it can't affect the distribution in any way.
Note also that you can subclass 'Feature' to create your own specialized
feature types that modify the distribution in other ways when included or
excluded. See the docstrings for the various methods here for more detail.
Aside from the methods, the only feature attributes that distributions look
at are 'description' and 'optional'.
"""
@
staticmethod
def
warn_deprecated
():
msg
=
(
"Features are deprecated and will be removed in a future "
"version. See https://github.com/pypa/setuptools/issues/65."
)
warnings
.
warn
(
msg
,
DistDeprecationWarning
,
stacklevel
=
3
)
def
__init__
(
self
,
description
,
standard
=
False
,
available
=
True
,
optional
=
True
,
require_features
=
(),
remove
=
(),
**
extras
):
self
.
warn_deprecated
()
self
.
description
=
description
self
.
standard
=
standard
self
.
available
=
available
self
.
optional
=
optional
if
isinstance
(
require_features
,
(
str
,
Require
)):
require_features
=
require_features
,
self
.
require_features
=
[
r
for
r
in
require_features
if
isinstance
(
r
,
str
)
]
er
=
[
r
for
r
in
require_features
if
not
isinstance
(
r
,
str
)]
if
er
:
extras
[
'require_features'
]
=
er
if
isinstance
(
remove
,
str
):
remove
=
remove
,
self
.
remove
=
remove
self
.
extras
=
extras
if
not
remove
and
not
require_features
and
not
extras
:
raise
DistutilsSetupError
(
"Feature %s: must define 'require_features', 'remove', or "
"at least one of 'packages', 'py_modules', etc."
)
def
include_by_default
(
self
):
"""Should this feature be included by default?"""
return
self
.
available
and
self
.
standard
def
include_in
(
self
,
dist
):
"""Ensure feature and its requirements are included in distribution
You may override this in a subclass to perform additional operations on
the distribution. Note that this method may be called more than once
per feature, and so should be idempotent.
"""
if
not
self
.
available
:
raise
DistutilsPlatformError
(
self
.
description
+
" is required, "
"but is not available on this platform"
)
dist
.
include
(
**
self
.
extras
)
for
f
in
self
.
require_features
:
dist
.
include_feature
(
f
)
def
exclude_from
(
self
,
dist
):
"""Ensure feature is excluded from distribution
You may override this in a subclass to perform additional operations on
the distribution. This method will be called at most once per
feature, and only after all included features have been asked to
include themselves.
"""
dist
.
exclude
(
**
self
.
extras
)
if
self
.
remove
:
for
item
in
self
.
remove
:
dist
.
exclude_package
(
item
)
def
validate
(
self
,
dist
):
"""Verify that feature makes sense in context of distribution
This method is called by the distribution just before it parses its
command line. It checks to ensure that the 'remove' attribute, if any,
contains only valid package/module names that are present in the base
distribution when 'setup()' is called. You may override it in a
subclass to perform any other required validation of the feature
against a target distribution.
"""
for
item
in
self
.
remove
:
if
not
dist
.
has_contents_for
(
item
):
raise
DistutilsSetupError
(
"%s wants to be able to remove %s, but the distribution"
" doesn't contain any packages or modules under %s"
%
(
self
.
description
,
item
,
item
)
)
class
DistDeprecationWarning
(
SetuptoolsDeprecationWarning
):
"""Class for warning about deprecations in dist in
setuptools. Not ignored by default, unlike DeprecationWarning."""
setuptools/tests/test_setuptools.py
View file @
dfd59c2a
...
...
@@ -4,7 +4,7 @@ import sys
import
os
import
distutils.core
import
distutils.cmd
from
distutils.errors
import
DistutilsOptionError
,
DistutilsPlatformError
from
distutils.errors
import
DistutilsOptionError
from
distutils.errors
import
DistutilsSetupError
from
distutils.core
import
Extension
from
distutils.version
import
LooseVersion
...
...
@@ -14,7 +14,6 @@ import pytest
import
setuptools
import
setuptools.dist
import
setuptools.depends
as
dep
from
setuptools
import
Feature
from
setuptools.depends
import
Require
from
setuptools.extern
import
six
...
...
@@ -216,86 +215,6 @@ class TestDistro:
self
.
dist
.
exclude
(
package_dir
=
[
'q'
])
@
pytest
.
mark
.
filterwarnings
(
'ignore:Features are deprecated'
)
class
TestFeatures
:
def
setup_method
(
self
,
method
):
self
.
req
=
Require
(
'Distutils'
,
'1.0.3'
,
'distutils'
)
self
.
dist
=
makeSetup
(
features
=
{
'foo'
:
Feature
(
"foo"
,
standard
=
True
,
require_features
=
[
'baz'
,
self
.
req
]),
'bar'
:
Feature
(
"bar"
,
standard
=
True
,
packages
=
[
'pkg.bar'
],
py_modules
=
[
'bar_et'
],
remove
=
[
'bar.ext'
],
),
'baz'
:
Feature
(
"baz"
,
optional
=
False
,
packages
=
[
'pkg.baz'
],
scripts
=
[
'scripts/baz_it'
],
libraries
=
[(
'libfoo'
,
'foo/foofoo.c'
)]
),
'dwim'
:
Feature
(
"DWIM"
,
available
=
False
,
remove
=
'bazish'
),
},
script_args
=
[
'--without-bar'
,
'install'
],
packages
=
[
'pkg.bar'
,
'pkg.foo'
],
py_modules
=
[
'bar_et'
,
'bazish'
],
ext_modules
=
[
Extension
(
'bar.ext'
,
[
'bar.c'
])]
)
def
testDefaults
(
self
):
assert
not
Feature
(
"test"
,
standard
=
True
,
remove
=
'x'
,
available
=
False
).
include_by_default
()
assert
Feature
(
"test"
,
standard
=
True
,
remove
=
'x'
).
include_by_default
()
# Feature must have either kwargs, removes, or require_features
with
pytest
.
raises
(
DistutilsSetupError
):
Feature
(
"test"
)
def
testAvailability
(
self
):
with
pytest
.
raises
(
DistutilsPlatformError
):
self
.
dist
.
features
[
'dwim'
].
include_in
(
self
.
dist
)
def
testFeatureOptions
(
self
):
dist
=
self
.
dist
assert
(
(
'with-dwim'
,
None
,
'include DWIM'
)
in
dist
.
feature_options
)
assert
(
(
'without-dwim'
,
None
,
'exclude DWIM (default)'
)
in
dist
.
feature_options
)
assert
(
(
'with-bar'
,
None
,
'include bar (default)'
)
in
dist
.
feature_options
)
assert
(
(
'without-bar'
,
None
,
'exclude bar'
)
in
dist
.
feature_options
)
assert
dist
.
feature_negopt
[
'without-foo'
]
==
'with-foo'
assert
dist
.
feature_negopt
[
'without-bar'
]
==
'with-bar'
assert
dist
.
feature_negopt
[
'without-dwim'
]
==
'with-dwim'
assert
(
'without-baz'
not
in
dist
.
feature_negopt
)
def
testUseFeatures
(
self
):
dist
=
self
.
dist
assert
dist
.
with_foo
==
1
assert
dist
.
with_bar
==
0
assert
dist
.
with_baz
==
1
assert
(
'bar_et'
not
in
dist
.
py_modules
)
assert
(
'pkg.bar'
not
in
dist
.
packages
)
assert
(
'pkg.baz'
in
dist
.
packages
)
assert
(
'scripts/baz_it'
in
dist
.
scripts
)
assert
((
'libfoo'
,
'foo/foofoo.c'
)
in
dist
.
libraries
)
assert
dist
.
ext_modules
==
[]
assert
dist
.
require_features
==
[
self
.
req
]
# If we ask for bar, it should fail because we explicitly disabled
# it on the command line
with
pytest
.
raises
(
DistutilsOptionError
):
dist
.
include_feature
(
'bar'
)
def
testFeatureWithInvalidRemove
(
self
):
with
pytest
.
raises
(
SystemExit
):
makeSetup
(
features
=
{
'x'
:
Feature
(
'x'
,
remove
=
'y'
)})
class
TestCommandTests
:
def
testTestIsCommand
(
self
):
test_cmd
=
makeSetup
().
get_command_obj
(
'test'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment