aboutsummaryrefslogtreecommitdiff
path: root/setuptools/command/egg_info.py
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools/command/egg_info.py')
-rw-r--r--[-rwxr-xr-x]setuptools/command/egg_info.py293
1 files changed, 170 insertions, 123 deletions
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index f3e604d..6338965 100755..100644
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -8,6 +8,7 @@ from distutils.util import convert_path
from distutils import log
import distutils.errors
import distutils.filelist
+import functools
import os
import re
import sys
@@ -16,8 +17,8 @@ import warnings
import time
import collections
-from setuptools.extern import six
-from setuptools.extern.six.moves import map
+from .._importlib import metadata
+from .. import _entry_points
from setuptools import Command
from setuptools.command.sdist import sdist
@@ -25,15 +26,17 @@ from setuptools.command.sdist import walk_revctrl
from setuptools.command.setopt import edit_config
from setuptools.command import bdist_egg
from pkg_resources import (
- parse_requirements, safe_name, parse_version,
- safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
+ Requirement, safe_name, parse_version,
+ safe_version, to_filename)
import setuptools.unicode_utils as unicode_utils
from setuptools.glob import glob
from setuptools.extern import packaging
+from setuptools.extern.jaraco.text import yield_lines
+from setuptools import SetuptoolsDeprecationWarning
-def translate_pattern(glob):
+def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME
"""
Translate a file path glob like '*.txt' in to a regular expression.
This differs from fnmatch.translate which allows wildcards to match
@@ -113,10 +116,41 @@ def translate_pattern(glob):
pat += sep
pat += r'\Z'
- return re.compile(pat, flags=re.MULTILINE|re.DOTALL)
+ return re.compile(pat, flags=re.MULTILINE | re.DOTALL)
-class egg_info(Command):
+class InfoCommon:
+ tag_build = None
+ tag_date = None
+
+ @property
+ def name(self):
+ return safe_name(self.distribution.get_name())
+
+ def tagged_version(self):
+ return safe_version(self._maybe_tag(self.distribution.get_version()))
+
+ def _maybe_tag(self, version):
+ """
+ egg_info may be called more than once for a distribution,
+ in which case the version string already contains all tags.
+ """
+ return (
+ version if self.vtags and version.endswith(self.vtags)
+ else version + self.vtags
+ )
+
+ def tags(self):
+ version = ''
+ if self.tag_build:
+ version += self.tag_build
+ if self.tag_date:
+ version += time.strftime("-%Y%m%d")
+ return version
+ vtags = property(tags)
+
+
+class egg_info(InfoCommon, Command):
description = "create a distribution's .egg-info directory"
user_options = [
@@ -133,14 +167,11 @@ class egg_info(Command):
}
def initialize_options(self):
- self.egg_name = None
- self.egg_version = None
self.egg_base = None
+ self.egg_name = None
self.egg_info = None
- self.tag_build = None
- self.tag_date = 0
+ self.egg_version = None
self.broken_egg_info = False
- self.vtags = None
####################################
# allow the 'tag_svn_revision' to be detected and
@@ -168,25 +199,23 @@ class egg_info(Command):
edit_config(filename, dict(egg_info=egg_info))
def finalize_options(self):
- self.egg_name = safe_name(self.distribution.get_name())
- self.vtags = self.tags()
+ # Note: we need to capture the current value returned
+ # by `self.tagged_version()`, so we can later update
+ # `self.distribution.metadata.version` without
+ # repercussions.
+ self.egg_name = self.name
self.egg_version = self.tagged_version()
-
parsed_version = parse_version(self.egg_version)
try:
is_version = isinstance(parsed_version, packaging.version.Version)
- spec = (
- "%s==%s" if is_version else "%s===%s"
- )
- list(
- parse_requirements(spec % (self.egg_name, self.egg_version))
- )
- except ValueError:
+ spec = "%s==%s" if is_version else "%s===%s"
+ Requirement(spec % (self.egg_name, self.egg_version))
+ except ValueError as e:
raise distutils.errors.DistutilsOptionError(
"Invalid distribution name or version syntax: %s-%s" %
(self.egg_name, self.egg_version)
- )
+ ) from e
if self.egg_base is None:
dirs = self.distribution.package_dir
@@ -241,8 +270,7 @@ class egg_info(Command):
to the file.
"""
log.info("writing %s to %s", what, filename)
- if six.PY3:
- data = data.encode("utf-8")
+ data = data.encode("utf-8")
if not self.dry_run:
f = open(filename, 'wb')
f.write(data)
@@ -254,20 +282,12 @@ class egg_info(Command):
if not self.dry_run:
os.unlink(filename)
- def tagged_version(self):
- version = self.distribution.get_version()
- # egg_info may be called more than once for a distribution,
- # in which case the version string already contains all tags.
- if self.vtags and version.endswith(self.vtags):
- return safe_version(version)
- return safe_version(version + self.vtags)
-
def run(self):
self.mkpath(self.egg_info)
- installer = self.distribution.fetch_build_egg
- for ep in iter_entry_points('egg_info.writers'):
- ep.require(installer=installer)
- writer = ep.resolve()
+ os.utime(self.egg_info, None)
+ for ep in metadata.entry_points(group='egg_info.writers'):
+ self.distribution._install_dependencies(ep)
+ writer = ep.load()
writer(self, ep.name, os.path.join(self.egg_info, ep.name))
# Get rid of native_libs.txt if it was put there by older bdist_egg
@@ -277,14 +297,6 @@ class egg_info(Command):
self.find_sources()
- def tags(self):
- version = ''
- if self.tag_build:
- version += self.tag_build
- if self.tag_date:
- version += time.strftime("-%Y%m%d")
- return version
-
def find_sources(self):
"""Generate SOURCES.txt manifest file"""
manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
@@ -320,70 +332,74 @@ class FileList(_FileList):
# patterns, (dir and patterns), or (dir_pattern).
(action, patterns, dir, dir_pattern) = self._parse_template_line(line)
+ action_map = {
+ 'include': self.include,
+ 'exclude': self.exclude,
+ 'global-include': self.global_include,
+ 'global-exclude': self.global_exclude,
+ 'recursive-include': functools.partial(
+ self.recursive_include, dir,
+ ),
+ 'recursive-exclude': functools.partial(
+ self.recursive_exclude, dir,
+ ),
+ 'graft': self.graft,
+ 'prune': self.prune,
+ }
+ log_map = {
+ 'include': "warning: no files found matching '%s'",
+ 'exclude': (
+ "warning: no previously-included files found "
+ "matching '%s'"
+ ),
+ 'global-include': (
+ "warning: no files found matching '%s' "
+ "anywhere in distribution"
+ ),
+ 'global-exclude': (
+ "warning: no previously-included files matching "
+ "'%s' found anywhere in distribution"
+ ),
+ 'recursive-include': (
+ "warning: no files found matching '%s' "
+ "under directory '%s'"
+ ),
+ 'recursive-exclude': (
+ "warning: no previously-included files matching "
+ "'%s' found under directory '%s'"
+ ),
+ 'graft': "warning: no directories found matching '%s'",
+ 'prune': "no previously-included directories found matching '%s'",
+ }
+
+ try:
+ process_action = action_map[action]
+ except KeyError:
+ raise DistutilsInternalError(
+ "this cannot happen: invalid action '{action!s}'".
+ format(action=action),
+ )
+
# OK, now we know that the action is valid and we have the
# right number of words on the line for that action -- so we
# can proceed with minimal error-checking.
- if action == 'include':
- self.debug_print("include " + ' '.join(patterns))
- for pattern in patterns:
- if not self.include(pattern):
- log.warn("warning: no files found matching '%s'", pattern)
-
- elif action == 'exclude':
- self.debug_print("exclude " + ' '.join(patterns))
- for pattern in patterns:
- if not self.exclude(pattern):
- log.warn(("warning: no previously-included files "
- "found matching '%s'"), pattern)
-
- elif action == 'global-include':
- self.debug_print("global-include " + ' '.join(patterns))
- for pattern in patterns:
- if not self.global_include(pattern):
- log.warn(("warning: no files found matching '%s' "
- "anywhere in distribution"), pattern)
-
- elif action == 'global-exclude':
- self.debug_print("global-exclude " + ' '.join(patterns))
- for pattern in patterns:
- if not self.global_exclude(pattern):
- log.warn(("warning: no previously-included files matching "
- "'%s' found anywhere in distribution"),
- pattern)
-
- elif action == 'recursive-include':
- self.debug_print("recursive-include %s %s" %
- (dir, ' '.join(patterns)))
- for pattern in patterns:
- if not self.recursive_include(dir, pattern):
- log.warn(("warning: no files found matching '%s' "
- "under directory '%s'"),
- pattern, dir)
-
- elif action == 'recursive-exclude':
- self.debug_print("recursive-exclude %s %s" %
- (dir, ' '.join(patterns)))
- for pattern in patterns:
- if not self.recursive_exclude(dir, pattern):
- log.warn(("warning: no previously-included files matching "
- "'%s' found under directory '%s'"),
- pattern, dir)
-
- elif action == 'graft':
- self.debug_print("graft " + dir_pattern)
- if not self.graft(dir_pattern):
- log.warn("warning: no directories found matching '%s'",
- dir_pattern)
-
- elif action == 'prune':
- self.debug_print("prune " + dir_pattern)
- if not self.prune(dir_pattern):
- log.warn(("no previously-included directories found "
- "matching '%s'"), dir_pattern)
-
- else:
- raise DistutilsInternalError(
- "this cannot happen: invalid action '%s'" % action)
+
+ action_is_recursive = action.startswith('recursive-')
+ if action in {'graft', 'prune'}:
+ patterns = [dir_pattern]
+ extra_log_args = (dir, ) if action_is_recursive else ()
+ log_tmpl = log_map[action]
+
+ self.debug_print(
+ ' '.join(
+ [action] +
+ ([dir] if action_is_recursive else []) +
+ patterns,
+ )
+ )
+ for pattern in patterns:
+ if not process_action(pattern):
+ log.warn(log_tmpl, pattern, *extra_log_args)
def _remove_files(self, predicate):
"""
@@ -524,6 +540,7 @@ class manifest_maker(sdist):
self.add_defaults()
if os.path.exists(self.template):
self.read_template()
+ self.add_license_files()
self.prune_file_list()
self.filelist.sort()
self.filelist.remove_duplicates()
@@ -565,9 +582,22 @@ class manifest_maker(sdist):
self.filelist.extend(rcfiles)
elif os.path.exists(self.manifest):
self.read_manifest()
+
+ if os.path.exists("setup.py"):
+ # setup.py should be included by default, even if it's not
+ # the script called to create the sdist
+ self.filelist.append("setup.py")
+
ei_cmd = self.get_finalized_command('egg_info')
self.filelist.graft(ei_cmd.egg_info)
+ def add_license_files(self):
+ license_files = self.distribution.metadata.license_files or []
+ for lf in license_files:
+ log.info("adding license file '%s'", lf)
+ pass
+ self.filelist.extend(license_files)
+
def prune_file_list(self):
build = self.get_finalized_command('build')
base_dir = self.distribution.get_fullname()
@@ -577,6 +607,27 @@ class manifest_maker(sdist):
self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
is_regex=1)
+ def _safe_data_files(self, build_py):
+ """
+ The parent class implementation of this method
+ (``sdist``) will try to include data files, which
+ might cause recursion problems when
+ ``include_package_data=True``.
+
+ Therefore, avoid triggering any attempt of
+ analyzing/building the manifest again.
+ """
+ if hasattr(build_py, 'get_data_files_without_manifest'):
+ return build_py.get_data_files_without_manifest()
+
+ warnings.warn(
+ "Custom 'build_py' does not implement "
+ "'get_data_files_without_manifest'.\nPlease extend command classes"
+ " from setuptools instead of distutils.",
+ SetuptoolsDeprecationWarning
+ )
+ return build_py.get_data_files()
+
def write_file(filename, contents):
"""Create a file with the specified name and write 'contents' (a
@@ -620,14 +671,16 @@ def warn_depends_obsolete(cmd, basename, filename):
def _write_requirements(stream, reqs):
lines = yield_lines(reqs or ())
- append_cr = lambda line: line + '\n'
+
+ def append_cr(line):
+ return line + '\n'
lines = map(append_cr, lines)
stream.writelines(lines)
def write_requirements(cmd, basename, filename):
dist = cmd.distribution
- data = six.StringIO()
+ data = io.StringIO()
_write_requirements(data, dist.install_requires)
extras_require = dist.extras_require or {}
for extra in sorted(extras_require):
@@ -665,20 +718,9 @@ def write_arg(cmd, basename, filename, force=False):
def write_entries(cmd, basename, filename):
- ep = cmd.distribution.entry_points
-
- if isinstance(ep, six.string_types) or ep is None:
- data = ep
- elif ep is not None:
- data = []
- for section, contents in sorted(ep.items()):
- if not isinstance(contents, six.string_types):
- contents = EntryPoint.parse_group(section, contents)
- contents = '\n'.join(sorted(map(str, contents.values())))
- data.append('[%s]\n%s\n\n' % (section, contents))
- data = ''.join(data)
-
- cmd.write_or_delete_file('entry points', filename, data, True)
+ eps = _entry_points.load(cmd.distribution.entry_points)
+ defn = _entry_points.render(eps)
+ cmd.write_or_delete_file('entry points', filename, defn, True)
def get_pkg_info_revision():
@@ -686,7 +728,8 @@ def get_pkg_info_revision():
Get a -r### off of PKG-INFO Version in case this is an sdist of
a subversion revision.
"""
- warnings.warn("get_pkg_info_revision is deprecated.", DeprecationWarning)
+ warnings.warn(
+ "get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning)
if os.path.exists('PKG-INFO'):
with io.open('PKG-INFO') as f:
for line in f:
@@ -694,3 +737,7 @@ def get_pkg_info_revision():
if match:
return int(match.group(1))
return 0
+
+
+class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning):
+ """Deprecated behavior warning for EggInfo, bypassing suppression."""