From: DongHun Kwak Date: Mon, 14 Jan 2019 01:34:49 +0000 (+0900) Subject: Imported Upstream version 36.4.0 X-Git-Tag: upstream/36.4.0^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fa5b1202ad31245629f6da0780accd0dce6cdeae;p=platform%2Fupstream%2Fpython-setuptools.git Imported Upstream version 36.4.0 --- diff --git a/CHANGES.rst b/CHANGES.rst index 1392e2a..8130511 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,27 @@ +v36.4.0 +------- + +* #1075: Add new ``Description-Content-Type`` metadata field. `See here for + documentation on how to use this field. + `_ + +* #1068: Sort files and directories when building eggs for + deterministic order. + +* #196: Remove caching of easy_install command in fetch_build_egg. + Fixes issue where ``pytest-runner-N.N`` would satisfy the installation + of ``pytest``. + +* #1129: Fix working set dependencies handling when replacing conflicting + distributions (e.g. when using ``setup_requires`` with a conflicting + transitive dependency, fix #1124). + +* #1133: Improved handling of README files extensions and added + Markdown to the list of searched READMES. + +* #1135: Improve performance of pkg_resources import by not invoking + ``access`` or ``stat`` and using ``os.listdir`` instead. + v36.3.0 ------- diff --git a/docs/setuptools.txt b/docs/setuptools.txt index 45d746d..531d727 100644 --- a/docs/setuptools.txt +++ b/docs/setuptools.txt @@ -2394,27 +2394,28 @@ Metadata Aliases given below are supported for compatibility reasons, but not advised. -================= ================= ===== -Key Aliases Accepted value type -================= ================= ===== -name str -version attr:, str -url home-page str -download_url download-url str -author str -author_email author-email str -maintainer str -maintainer_email maintainer-email str -classifiers classifier file:, list-comma -license file:, str -description summary file:, str -long_description long-description file:, str -keywords list-comma -platforms platform list-comma -provides list-comma -requires list-comma -obsoletes list-comma -================= ================= ===== +============================== ================= ===== +Key Aliases Accepted value type +============================== ================= ===== +name str +version attr:, str +url home-page str +download_url download-url str +author str +author_email author-email str +maintainer str +maintainer_email maintainer-email str +classifiers classifier file:, list-comma +license file:, str +description summary file:, str +long_description long-description file:, str +long_description_content_type str +keywords list-comma +platforms platform list-comma +provides list-comma +requires list-comma +obsoletes list-comma +============================== ================= ===== .. note:: diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index f13a69b..ce6053f 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -34,6 +34,7 @@ import platform import collections import plistlib import email.parser +import errno import tempfile import textwrap import itertools @@ -80,6 +81,11 @@ __import__('pkg_resources.extern.packaging.markers') if (3, 0) < sys.version_info < (3, 3): raise RuntimeError("Python 3.3 or later is required") +if six.PY2: + # Those builtin exceptions are only defined in Python 3 + PermissionError = None + NotADirectoryError = None + # declare some globals that will be defined later to # satisfy the linters. require = None @@ -852,7 +858,10 @@ class WorkingSet(object): # distribution env = Environment([]) ws = WorkingSet([]) - dist = best[req.key] = env.best_match(req, ws, installer) + dist = best[req.key] = env.best_match( + req, ws, installer, + replace_conflicting=replace_conflicting + ) if dist is None: requirers = required_by.get(req, None) raise DistributionNotFound(req, requirers) @@ -1104,7 +1113,7 @@ class Environment(object): dists.append(dist) dists.sort(key=operator.attrgetter('hashcmp'), reverse=True) - def best_match(self, req, working_set, installer=None): + def best_match(self, req, working_set, installer=None, replace_conflicting=False): """Find distribution best matching `req` and usable on `working_set` This calls the ``find(req)`` method of the `working_set` to see if a @@ -1117,7 +1126,12 @@ class Environment(object): calling the environment's ``obtain(req, installer)`` method will be returned. """ - dist = working_set.find(req) + try: + dist = working_set.find(req) + except VersionConflict: + if not replace_conflicting: + raise + dist = None if dist is not None: return dist for dist in self[req.key]: @@ -2008,46 +2022,57 @@ def find_on_path(importer, path_item, only=False): """Yield distributions accessible on a sys.path directory""" path_item = _normalize_cached(path_item) - if os.path.isdir(path_item) and os.access(path_item, os.R_OK): - if _is_unpacked_egg(path_item): - yield Distribution.from_filename( - path_item, metadata=PathMetadata( - path_item, os.path.join(path_item, 'EGG-INFO') - ) + if _is_unpacked_egg(path_item): + yield Distribution.from_filename( + path_item, metadata=PathMetadata( + path_item, os.path.join(path_item, 'EGG-INFO') ) - else: - # scan for .egg and .egg-info in directory - path_item_entries = _by_version_descending(os.listdir(path_item)) - for entry in path_item_entries: - lower = entry.lower() - if lower.endswith('.egg-info') or lower.endswith('.dist-info'): - fullpath = os.path.join(path_item, entry) - if os.path.isdir(fullpath): - # egg-info directory, allow getting metadata - if len(os.listdir(fullpath)) == 0: - # Empty egg directory, skip. - continue - metadata = PathMetadata(path_item, fullpath) - else: - metadata = FileMetadata(fullpath) - yield Distribution.from_location( - path_item, entry, metadata, precedence=DEVELOP_DIST - ) - elif not only and _is_egg_path(entry): - dists = find_distributions(os.path.join(path_item, entry)) - for dist in dists: - yield dist - elif not only and lower.endswith('.egg-link'): - with open(os.path.join(path_item, entry)) as entry_file: - entry_lines = entry_file.readlines() - for line in entry_lines: - if not line.strip(): - continue - path = os.path.join(path_item, line.rstrip()) - dists = find_distributions(path) - for item in dists: - yield item - break + ) + else: + try: + entries = os.listdir(path_item) + except (PermissionError, NotADirectoryError): + return + except OSError as e: + # Ignore the directory if does not exist, not a directory or we + # don't have permissions + if (e.errno in (errno.ENOTDIR, errno.EACCES, errno.ENOENT) + # Python 2 on Windows needs to be handled this way :( + or hasattr(e, "winerror") and e.winerror == 267): + return + raise + # scan for .egg and .egg-info in directory + path_item_entries = _by_version_descending(entries) + for entry in path_item_entries: + lower = entry.lower() + if lower.endswith('.egg-info') or lower.endswith('.dist-info'): + fullpath = os.path.join(path_item, entry) + if os.path.isdir(fullpath): + # egg-info directory, allow getting metadata + if len(os.listdir(fullpath)) == 0: + # Empty egg directory, skip. + continue + metadata = PathMetadata(path_item, fullpath) + else: + metadata = FileMetadata(fullpath) + yield Distribution.from_location( + path_item, entry, metadata, precedence=DEVELOP_DIST + ) + elif not only and _is_egg_path(entry): + dists = find_distributions(os.path.join(path_item, entry)) + for dist in dists: + yield dist + elif not only and lower.endswith('.egg-link'): + with open(os.path.join(path_item, entry)) as entry_file: + entry_lines = entry_file.readlines() + for line in entry_lines: + if not line.strip(): + continue + path = os.path.join(path_item, line.rstrip()) + dists = find_distributions(path) + for item in dists: + yield item + break register_finder(pkgutil.ImpImporter, find_on_path) diff --git a/pkg_resources/tests/test_working_set.py b/pkg_resources/tests/test_working_set.py new file mode 100644 index 0000000..422a728 --- /dev/null +++ b/pkg_resources/tests/test_working_set.py @@ -0,0 +1,478 @@ +import inspect +import re +import textwrap + +import pytest + +import pkg_resources + +from .test_resources import Metadata + + +def strip_comments(s): + return '\n'.join( + l for l in s.split('\n') + if l.strip() and not l.strip().startswith('#') + ) + +def parse_distributions(s): + ''' + Parse a series of distribution specs of the form: + {project_name}-{version} + [optional, indented requirements specification] + + Example: + + foo-0.2 + bar-1.0 + foo>=3.0 + [feature] + baz + + yield 2 distributions: + - project_name=foo, version=0.2 + - project_name=bar, version=1.0, requires=['foo>=3.0', 'baz; extra=="feature"'] + ''' + s = s.strip() + for spec in re.split('\n(?=[^\s])', s): + if not spec: + continue + fields = spec.split('\n', 1) + assert 1 <= len(fields) <= 2 + name, version = fields.pop(0).split('-') + if fields: + requires = textwrap.dedent(fields.pop(0)) + metadata=Metadata(('requires.txt', requires)) + else: + metadata = None + dist = pkg_resources.Distribution(project_name=name, + version=version, + metadata=metadata) + yield dist + + +class FakeInstaller(object): + + def __init__(self, installable_dists): + self._installable_dists = installable_dists + + def __call__(self, req): + return next(iter(filter(lambda dist: dist in req, + self._installable_dists)), None) + + +def parametrize_test_working_set_resolve(*test_list): + idlist = [] + argvalues = [] + for test in test_list: + ( + name, + installed_dists, + installable_dists, + requirements, + expected1, expected2 + ) = [ + strip_comments(s.lstrip()) for s in + textwrap.dedent(test).lstrip().split('\n\n', 5) + ] + installed_dists = list(parse_distributions(installed_dists)) + installable_dists = list(parse_distributions(installable_dists)) + requirements = list(pkg_resources.parse_requirements(requirements)) + for id_, replace_conflicting, expected in ( + (name, False, expected1), + (name + '_replace_conflicting', True, expected2), + ): + idlist.append(id_) + expected = strip_comments(expected.strip()) + if re.match('\w+$', expected): + expected = getattr(pkg_resources, expected) + assert issubclass(expected, Exception) + else: + expected = list(parse_distributions(expected)) + argvalues.append(pytest.param(installed_dists, installable_dists, + requirements, replace_conflicting, + expected)) + return pytest.mark.parametrize('installed_dists,installable_dists,' + 'requirements,replace_conflicting,' + 'resolved_dists_or_exception', + argvalues, ids=idlist) + + +@parametrize_test_working_set_resolve( + ''' + # id + noop + + # installed + + # installable + + # wanted + + # resolved + + # resolved [replace conflicting] + ''', + + ''' + # id + already_installed + + # installed + foo-3.0 + + # installable + + # wanted + foo>=2.1,!=3.1,<4 + + # resolved + foo-3.0 + + # resolved [replace conflicting] + foo-3.0 + ''', + + ''' + # id + installable_not_installed + + # installed + + # installable + foo-3.0 + foo-4.0 + + # wanted + foo>=2.1,!=3.1,<4 + + # resolved + foo-3.0 + + # resolved [replace conflicting] + foo-3.0 + ''', + + ''' + # id + not_installable + + # installed + + # installable + + # wanted + foo>=2.1,!=3.1,<4 + + # resolved + DistributionNotFound + + # resolved [replace conflicting] + DistributionNotFound + ''', + + ''' + # id + no_matching_version + + # installed + + # installable + foo-3.1 + + # wanted + foo>=2.1,!=3.1,<4 + + # resolved + DistributionNotFound + + # resolved [replace conflicting] + DistributionNotFound + ''', + + ''' + # id + installable_with_installed_conflict + + # installed + foo-3.1 + + # installable + foo-3.5 + + # wanted + foo>=2.1,!=3.1,<4 + + # resolved + VersionConflict + + # resolved [replace conflicting] + foo-3.5 + ''', + + ''' + # id + not_installable_with_installed_conflict + + # installed + foo-3.1 + + # installable + + # wanted + foo>=2.1,!=3.1,<4 + + # resolved + VersionConflict + + # resolved [replace conflicting] + DistributionNotFound + ''', + + ''' + # id + installed_with_installed_require + + # installed + foo-3.9 + baz-0.1 + foo>=2.1,!=3.1,<4 + + # installable + + # wanted + baz + + # resolved + foo-3.9 + baz-0.1 + + # resolved [replace conflicting] + foo-3.9 + baz-0.1 + ''', + + ''' + # id + installed_with_conflicting_installed_require + + # installed + foo-5 + baz-0.1 + foo>=2.1,!=3.1,<4 + + # installable + + # wanted + baz + + # resolved + VersionConflict + + # resolved [replace conflicting] + DistributionNotFound + ''', + + ''' + # id + installed_with_installable_conflicting_require + + # installed + foo-5 + baz-0.1 + foo>=2.1,!=3.1,<4 + + # installable + foo-2.9 + + # wanted + baz + + # resolved + VersionConflict + + # resolved [replace conflicting] + baz-0.1 + foo-2.9 + ''', + + ''' + # id + installed_with_installable_require + + # installed + baz-0.1 + foo>=2.1,!=3.1,<4 + + # installable + foo-3.9 + + # wanted + baz + + # resolved + foo-3.9 + baz-0.1 + + # resolved [replace conflicting] + foo-3.9 + baz-0.1 + ''', + + ''' + # id + installable_with_installed_require + + # installed + foo-3.9 + + # installable + baz-0.1 + foo>=2.1,!=3.1,<4 + + # wanted + baz + + # resolved + foo-3.9 + baz-0.1 + + # resolved [replace conflicting] + foo-3.9 + baz-0.1 + ''', + + ''' + # id + installable_with_installable_require + + # installed + + # installable + foo-3.9 + baz-0.1 + foo>=2.1,!=3.1,<4 + + # wanted + baz + + # resolved + foo-3.9 + baz-0.1 + + # resolved [replace conflicting] + foo-3.9 + baz-0.1 + ''', + + ''' + # id + installable_with_conflicting_installable_require + + # installed + foo-5 + + # installable + foo-2.9 + baz-0.1 + foo>=2.1,!=3.1,<4 + + # wanted + baz + + # resolved + VersionConflict + + # resolved [replace conflicting] + baz-0.1 + foo-2.9 + ''', + + ''' + # id + conflicting_installables + + # installed + + # installable + foo-2.9 + foo-5.0 + + # wanted + foo>=2.1,!=3.1,<4 + foo>=4 + + # resolved + VersionConflict + + # resolved [replace conflicting] + VersionConflict + ''', + + ''' + # id + installables_with_conflicting_requires + + # installed + + # installable + foo-2.9 + dep==1.0 + baz-5.0 + dep==2.0 + dep-1.0 + dep-2.0 + + # wanted + foo + baz + + # resolved + VersionConflict + + # resolved [replace conflicting] + VersionConflict + ''', + + ''' + # id + installables_with_conflicting_nested_requires + + # installed + + # installable + foo-2.9 + dep1 + dep1-1.0 + subdep<1.0 + baz-5.0 + dep2 + dep2-1.0 + subdep>1.0 + subdep-0.9 + subdep-1.1 + + # wanted + foo + baz + + # resolved + VersionConflict + + # resolved [replace conflicting] + VersionConflict + ''', +) +def test_working_set_resolve(installed_dists, installable_dists, requirements, + replace_conflicting, resolved_dists_or_exception): + ws = pkg_resources.WorkingSet([]) + list(map(ws.add, installed_dists)) + resolve_call = lambda: ws.resolve( + requirements, installer=FakeInstaller(installable_dists), + replace_conflicting=replace_conflicting, + ) + if inspect.isclass(resolved_dists_or_exception): + with pytest.raises(resolved_dists_or_exception): + resolve_call() + else: + assert sorted(resolve_call()) == sorted(resolved_dists_or_exception) diff --git a/setup.cfg b/setup.cfg index ddc2a72..ea64989 100755 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 36.3.0 +current_version = 36.4.0 commit = True tag = True diff --git a/setup.py b/setup.py index d7a1344..eb939ff 100755 --- a/setup.py +++ b/setup.py @@ -89,12 +89,13 @@ def pypi_link(pkg_filename): setup_params = dict( name="setuptools", - version="36.3.0", + version="36.4.0", description="Easily download, build, install, upgrade, and uninstall " "Python packages", author="Python Packaging Authority", author_email="distutils-sig@python.org", long_description=long_description, + long_description_content_type='text/x-rst; charset=UTF-8', keywords="CPAN PyPI distutils eggs package management", url="https://github.com/pypa/setuptools", src_root=None, diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index 8cd9dfe..51755d5 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -38,6 +38,14 @@ def strip_module(filename): filename = filename[:-6] return filename +def sorted_walk(dir): + """Do os.walk in a reproducible way, + independent of indeterministic filesystem readdir order + """ + for base, dirs, files in os.walk(dir): + dirs.sort() + files.sort() + yield base, dirs, files def write_stub(resource, pyfile): _stub_template = textwrap.dedent(""" @@ -302,7 +310,7 @@ class bdist_egg(Command): ext_outputs = [] paths = {self.bdist_dir: ''} - for base, dirs, files in os.walk(self.bdist_dir): + for base, dirs, files in sorted_walk(self.bdist_dir): for filename in files: if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS: all_outputs.append(paths[base] + filename) @@ -329,7 +337,7 @@ NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split()) def walk_egg(egg_dir): """Walk an unpacked egg's contents, skipping the metadata directory""" - walker = os.walk(egg_dir) + walker = sorted_walk(egg_dir) base, dirs, files = next(walker) if 'EGG-INFO' in dirs: dirs.remove('EGG-INFO') @@ -463,10 +471,10 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True, compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED if not dry_run: z = zipfile.ZipFile(zip_filename, mode, compression=compression) - for dirname, dirs, files in os.walk(base_dir): + for dirname, dirs, files in sorted_walk(base_dir): visit(z, dirname, files) z.close() else: - for dirname, dirs, files in os.walk(base_dir): + for dirname, dirs, files in sorted_walk(base_dir): visit(None, dirname, files) return zip_filename diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 6c00b0b..a183d15 100755 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -599,6 +599,10 @@ def write_pkg_info(cmd, basename, filename): metadata = cmd.distribution.metadata metadata.version, oldver = cmd.egg_version, metadata.version metadata.name, oldname = cmd.egg_name, metadata.name + metadata.long_description_content_type = getattr( + cmd.distribution, + 'long_description_content_type' + ) try: # write unescaped data to PKG-INFO, so older pkg_resources # can still parse it diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 84e29a1..508148e 100755 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -37,7 +37,8 @@ class sdist(sdist_add_defaults, orig.sdist): negative_opt = {} - READMES = 'README', 'README.rst', 'README.txt' + README_EXTENSIONS = ['', '.rst', '.txt', '.md'] + READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS) def run(self): self.run_command('egg_info') diff --git a/setuptools/dist.py b/setuptools/dist.py index 21730f2..a2ca879 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -58,6 +58,13 @@ def write_pkg_file(self, file): if self.download_url: file.write('Download-URL: %s\n' % self.download_url) + long_desc_content_type = getattr( + self, + 'long_description_content_type', + None + ) or 'UNKNOWN' + file.write('Description-Content-Type: %s\n' % long_desc_content_type) + long_desc = rfc822_escape(self.get_long_description()) file.write('Description: %s\n' % long_desc) @@ -317,6 +324,9 @@ class Distribution(Distribution_parse_config_files, _Distribution): self.dist_files = [] self.src_root = attrs and attrs.pop("src_root", None) self.patch_missing_pkg_info(attrs) + self.long_description_content_type = _attrs_dict.get( + 'long_description_content_type' + ) # Make sure we have any eggs needed to interpret 'attrs' if attrs is not None: self.dependency_links = attrs.pop('dependency_links', []) @@ -485,36 +495,30 @@ class Distribution(Distribution_parse_config_files, _Distribution): def fetch_build_egg(self, req): """Fetch an egg needed for building""" - - try: - cmd = self._egg_fetcher - cmd.package_index.to_scan = [] - except AttributeError: - from setuptools.command.easy_install import easy_install - dist = self.__class__({'script_args': ['easy_install']}) - dist.parse_config_files() - opts = dist.get_option_dict('easy_install') - keep = ( - 'find_links', 'site_dirs', 'index_url', 'optimize', - 'site_dirs', 'allow_hosts' - ) - for key in list(opts): - if key not in keep: - del opts[key] # don't use any other settings - if self.dependency_links: - links = self.dependency_links[:] - if 'find_links' in opts: - links = opts['find_links'][1].split() + links - opts['find_links'] = ('setup', links) - install_dir = self.get_egg_cache_dir() - cmd = easy_install( - dist, args=["x"], install_dir=install_dir, - exclude_scripts=True, - always_copy=False, build_directory=None, editable=False, - upgrade=False, multi_version=True, no_report=True, user=False - ) - cmd.ensure_finalized() - self._egg_fetcher = cmd + from setuptools.command.easy_install import easy_install + dist = self.__class__({'script_args': ['easy_install']}) + dist.parse_config_files() + opts = dist.get_option_dict('easy_install') + keep = ( + 'find_links', 'site_dirs', 'index_url', 'optimize', + 'site_dirs', 'allow_hosts' + ) + for key in list(opts): + if key not in keep: + del opts[key] # don't use any other settings + if self.dependency_links: + links = self.dependency_links[:] + if 'find_links' in opts: + links = opts['find_links'][1].split() + links + opts['find_links'] = ('setup', links) + install_dir = self.get_egg_cache_dir() + cmd = easy_install( + dist, args=["x"], install_dir=install_dir, + exclude_scripts=True, + always_copy=False, build_directory=None, editable=False, + upgrade=False, multi_version=True, no_report=True, user=False + ) + cmd.ensure_finalized() return cmd.easy_install(req) def _set_global_opts_from_features(self): diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py new file mode 100644 index 0000000..435ffec --- /dev/null +++ b/setuptools/tests/test_dist.py @@ -0,0 +1,46 @@ +from setuptools import Distribution +from setuptools.extern.six.moves.urllib.request import pathname2url +from setuptools.extern.six.moves.urllib_parse import urljoin + +from .textwrap import DALS +from .test_easy_install import make_nspkg_sdist + + +def test_dist_fetch_build_egg(tmpdir): + """ + Check multiple calls to `Distribution.fetch_build_egg` work as expected. + """ + index = tmpdir.mkdir('index') + index_url = urljoin('file://', pathname2url(str(index))) + def sdist_with_index(distname, version): + dist_dir = index.mkdir(distname) + dist_sdist = '%s-%s.tar.gz' % (distname, version) + make_nspkg_sdist(str(dist_dir.join(dist_sdist)), distname, version) + with dist_dir.join('index.html').open('w') as fp: + fp.write(DALS( + ''' + + {dist_sdist}
+ + ''' + ).format(dist_sdist=dist_sdist)) + sdist_with_index('barbazquux', '3.2.0') + sdist_with_index('barbazquux-runner', '2.11.1') + with tmpdir.join('setup.cfg').open('w') as fp: + fp.write(DALS( + ''' + [easy_install] + index_url = {index_url} + ''' + ).format(index_url=index_url)) + reqs = ''' + barbazquux-runner + barbazquux + '''.split() + with tmpdir.as_cwd(): + dist = Distribution() + resolved_dists = [ + dist.fetch_build_egg(r) + for r in reqs + ] + assert [dist.key for dist in resolved_dists if dist] == reqs diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index 33d6cc5..e454694 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -398,6 +398,31 @@ class TestEggInfo(object): self._run_install_command(tmpdir_cwd, env) assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == [] + def test_long_description_content_type(self, tmpdir_cwd, env): + # Test that specifying a `long_description_content_type` keyword arg to + # the `setup` function results in writing a `Description-Content-Type` + # line to the `PKG-INFO` file in the `.egg-info` + # directory. + # `Description-Content-Type` is described at + # https://github.com/pypa/python-packaging-user-guide/pull/258 + + self._setup_script_with_requires( + """long_description_content_type='text/markdown',""") + environ = os.environ.copy().update( + HOME=env.paths['home'], + ) + code, data = environment.run_setup_py( + cmd=['egg_info'], + pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]), + data_stream=1, + env=environ, + ) + egg_info_dir = os.path.join('.', 'foo.egg-info') + with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file: + pkg_info_lines = pkginfo_file.read().split('\n') + expected_line = 'Description-Content-Type: text/markdown' + assert expected_line in pkg_info_lines + def test_python_requires_egg_info(self, tmpdir_cwd, env): self._setup_script_with_requires( """python_requires='>=2.7.12',""")