Commit e85ad92f authored by Jason R. Coombs's avatar Jason R. Coombs

Merge with 23.2.1

parents 54325a75 94d97d07
......@@ -264,3 +264,16 @@ ddd3f81eb9e0860bf95c380c50a72c52a215231f v21.0.0
40b8fac6db119aca9c462993d01908492769fc4f v21.2.0
40b8fac6db119aca9c462993d01908492769fc4f v21.2.0
9959424676a4aac1c14e430ff6f4210fdb0442d9 v21.2.0
694111eadb10fe6003078895a2cbb803ce514ef2 v21.2.1
274f33435e9c3ba5019f2a2bfe478fa2db0da41d v21.2.2
451fbedb4c226d8ea5b6eab1e21679c9a4ec4a93 v22.0.0
f5c4923b0400d61f67699c2d54388878f9e0c8bd v22.0.1
8610a8b9635f15d33f94fccb295fd34aa6fbddee v22.0.2
efee7d74a8478c0d08c801fb520e41b6e04d0dda v22.0.3
77b20c09b04775cc936ab5d16cbc46ff05fc7080 v22.0.4
d5832e5deb77027da474e79e5f047e9a81f7edf8 v22.0.5
8664c631bf3a817a7deba86c13b67eccc1f81091 v23.0.0
6c74559c732c56f61b465d613458ec1a930884b6 v23.1.0
65b3fe899db4086e66afa067a1311eea2a88d5e2 v23.2.0
e10c848a82ffb925741c65dd8a8fc8b50b3c3e14 v23.2.1
a011298221c3d47aa539ae4c119c51861caf6438 v23.2.1
......@@ -26,6 +26,8 @@ before_deploy:
- export SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES=1
deploy:
provider: pypi
# Also update server in setup.cfg
server: https://upload.pypi.io/legacy/
on:
tags: true
all_branches: true
......
......@@ -10,6 +10,83 @@ Next
* Renamed ``setuptools.msvc9_support`` to
``setuptools.msvc``.
v23.2.1
-------
Re-release of v23.2.0, which was missing the intended
commits.
* #623: Remove used of deprecated 'U' flag when reading
manifests.
v23.1.0
-------
* #619: Deprecated ``tag_svn_revision`` distribution
option.
v23.0.0
-------
* #611: Removed ARM executables for CLI and GUI script
launchers on Windows. If this was a feature you cared
about, please comment in the ticket.
* #604: Removed docs building support. The project
now relies on documentation hosted at
https://setuptools.readthedocs.io/.
v22.0.5
-------
* #604: Restore repository for upload_docs command
to restore publishing of docs during release.
v22.0.4
-------
* #589: Upload releases to pypi.io using the upload
hostname and legacy path.
v22.0.3
-------
* #589: Releases are now uploaded to pypi.io (Warehouse)
even when releases are made on Twine via Travis.
v22.0.2
-------
* #589: Releases are now uploaded to pypi.io (Warehouse).
v22.0.1
-------
* #190: On Python 2, if unicode is passed for packages to
``build_py`` command, it will be handled just as with
text on Python 3.
v22.0.0
-------
Intended to be v21.3.0, but jaraco accidentally released as
a major bump.
* #598: Setuptools now lists itself first in the User-Agent
for web requests, better following the guidelines in
`RFC 7231
<https://tools.ietf.org/html/rfc7231#section-5.5.3>`_.
v21.2.2
-------
* Minor fixes to changelog and docs.
v21.2.1
-------
* #261: Exclude directories when resolving globs in
package_data.
v21.2.0
-------
......@@ -111,7 +188,7 @@ v20.6.0
20.5
----
* BB Pull Request #185: Add support for environment markers
* BB Pull Request #185, #470: Add support for environment markers
in requirements in install_requires, setup_requires,
tests_require as well as adding a test for the existing
extra_requires machinery.
......
......@@ -5,7 +5,8 @@ Installing and Using Setuptools
.. contents:: **Table of Contents**
`Change History <https://pythonhosted.org/setuptools/history.html>`_.
.. image:: https://setuptools.readthedocs.io/en/latest/?badge=latest
:target: https://setuptools.readthedocs.io
-------------------------
Installation Instructions
......@@ -36,6 +37,10 @@ Powershell command. Start up Powershell and paste this command::
> (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python -
.. image:: https://badges.gitter.im/pypa/setuptools.svg
:alt: Join the chat at https://gitter.im/pypa/setuptools
:target: https://gitter.im/pypa/setuptools?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
You must start the Powershell with Administrative privileges or you may choose
to install a user-local installation::
......@@ -177,10 +182,10 @@ them there, so this reference list can be updated. If you have working,
the `setuptools bug tracker`_.
.. _setuptools bug tracker: https://github.com/pypa/setuptools/issues
.. _The Internal Structure of Python Eggs: https://pythonhosted.org/setuptools/formats.html
.. _The setuptools Developer's Guide: https://pythonhosted.org/setuptools/setuptools.html
.. _The pkg_resources API reference: https://pythonhosted.org/setuptools/pkg_resources.html
.. _The EasyInstall user's guide and reference manual: https://pythonhosted.org/setuptools/easy_install.html
.. _The Internal Structure of Python Eggs: https://setuptools.readthedocs.io/en/latest/formats.html
.. _The setuptools Developer's Guide: https://setuptools.readthedocs.io/en/latest/developer-guide.html
.. _The pkg_resources API reference: https://setuptools.readthedocs.io/en/latest/pkg_resources.html
.. _The EasyInstall user's guide and reference manual: https://setuptools.readthedocs.io/en/latest/easy_install.html
.. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/
......
......@@ -200,7 +200,7 @@ latex_documents = [
#latex_use_modindex = True
link_files = {
'CHANGES.rst': dict(
'../CHANGES.rst': dict(
using=dict(
BB='https://bitbucket.org',
GH='https://github.com',
......
......@@ -677,7 +677,7 @@ locations, build options, etc., EasyInstall will respect your existing settings
until and unless you override them explicitly in an ``[easy_install]`` section.
For more information, see also the current Python documentation on the `use and
location of distutils configuration files <http://docs.python.org/inst/config-syntax.html>`_.
location of distutils configuration files <https://docs.python.org/install/index.html#inst-config-files>`_.
Notice that ``easy_install`` will use the ``setup.cfg`` from the current
working directory only if it was triggered from ``setup.py`` through the
......
rst.linker>=1.6.1
......@@ -917,7 +917,7 @@ use its resource management API. See also `Accessing Package Resources`_ for
a quick example of converting code that uses ``__file__`` to use
``pkg_resources`` instead.
.. _Resource Management API: http://peak.telecommunity.com/DevCenter/PythonEggs#resource-management
.. _Resource Management API: http://peak.telecommunity.com/DevCenter/PkgResources#resourcemanager-api
.. _Accessing Package Resources: http://peak.telecommunity.com/DevCenter/PythonEggs#accessing-package-resources
......
......@@ -35,21 +35,5 @@ if "%ERRORLEVEL%"=="0" (
echo Windows SDK 6.1 not found to build Windows 64-bit version
)
REM Windows RT ARM build requires both freeware
REM "Visual Studio Express 2012 for Windows 8" and
REM "Visual Studio Express 2012 for Windows Desktop" to be installed from
REM http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-products
set PATH=%PATH_OLD%
set PATH=C:\Program Files\Microsoft Visual Studio 11.0\VC;%PATH%
set PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC;%PATH%
call VCVARSALL x86_arm >nul 2>&1
if "%ERRORLEVEL%"=="0" (
echo Building Windows RT Version ...
cl /D "GUI=0" /D "WIN32_LEAN_AND_MEAN" /D _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE launcher.c /O2 /link /MACHINE:ARM /SUBSYSTEM:CONSOLE /out:setuptools/cli-arm-32.exe
cl /D "GUI=1" /D "WIN32_LEAN_AND_MEAN" /D _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE launcher.c /O2 /link /MACHINE:ARM /SUBSYSTEM:WINDOWS /out:setuptools/gui-arm-32.exe
) else (
echo Visual Studio ^(Express^) 2012 not found to build Windows RT Version
)
set PATH=%PATH_OLD%
[bumpversion]
current_version = 21.2.0
current_version = 23.2.1
commit = True
tag = True
......@@ -9,18 +9,13 @@ tag_date = 1
[aliases]
clean_egg_info = egg_info -RDb ''
release = clean_egg_info sdist bdist_wheel build_sphinx
release = clean_egg_info sdist bdist_wheel
source = register sdist binary
binary = bdist_egg upload --show-response
test = pytest
[build_sphinx]
source-dir = docs/
build-dir = docs/build
all_files = 1
[upload_docs]
upload-dir = docs/build/html
[upload]
repository = https://upload.pypi.io/legacy/
[sdist]
formats = gztar zip
......
......@@ -61,14 +61,12 @@ if (sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt')) \
needs_pytest = set(['ptr', 'pytest', 'test']).intersection(sys.argv)
pytest_runner = ['pytest-runner'] if needs_pytest else []
needs_sphinx = set(['build_sphinx', 'upload_docs', 'release']).intersection(sys.argv)
sphinx = ['sphinx', 'rst.linker>=1.5'] if needs_sphinx else []
needs_wheel = set(['release', 'bdist_wheel']).intersection(sys.argv)
wheel = ['wheel'] if needs_wheel else []
setup_params = dict(
name="setuptools",
version="21.2.0",
version="23.2.1",
description="Easily download, build, install, upgrade, and uninstall "
"Python packages",
author="Python Packaging Authority",
......@@ -158,7 +156,7 @@ setup_params = dict(
'pytest>=2.8',
] + (['mock'] if sys.version_info[:2] < (3, 3) else []),
setup_requires=[
] + sphinx + pytest_runner + wheel,
] + pytest_runner + wheel,
)
if __name__ == '__main__':
......
......@@ -6,10 +6,10 @@ import fnmatch
import textwrap
import io
import distutils.errors
import collections
import itertools
from setuptools.extern.six.moves import map
from setuptools.extern import six
from setuptools.extern.six.moves import map, filter, filterfalse
try:
from setuptools.lib2to3_ex import Mixin2to3
......@@ -67,6 +67,9 @@ class build_py(orig.build_py, Mixin2to3):
return orig.build_py.__getattr__(self, attr)
def build_module(self, module, module_file, package):
if six.PY2 and isinstance(package, six.string_types):
# avoid errors on Python 2 when unicode is passed (#190)
package = package.split('.')
outfile, copied = orig.build_py.build_module(self, module, module_file,
package)
if copied:
......@@ -94,12 +97,19 @@ class build_py(orig.build_py, Mixin2to3):
def find_data_files(self, package, src_dir):
"""Return filenames for package's data files in 'src_dir'"""
globs = (self.package_data.get('', [])
+ self.package_data.get(package, []))
files = self.manifest_files.get(package, [])[:]
for pattern in globs:
# Each pattern has to be converted to a platform-specific path
files.extend(glob(os.path.join(src_dir, convert_path(pattern))))
patterns = self._get_platform_patterns(
self.package_data,
package,
src_dir,
)
globs_expanded = map(glob, patterns)
# flatten the expanded globs into an iterable of matches
globs_matches = itertools.chain.from_iterable(globs_expanded)
glob_files = filter(os.path.isfile, globs_matches)
files = itertools.chain(
self.manifest_files.get(package, []),
glob_files,
)
return self.exclude_data_files(package, src_dir, files)
def build_package_data(self):
......@@ -184,26 +194,63 @@ class build_py(orig.build_py, Mixin2to3):
def exclude_data_files(self, package, src_dir, files):
"""Filter filenames for package's data files in 'src_dir'"""
globs = (
self.exclude_package_data.get('', [])
+ self.exclude_package_data.get(package, [])
files = list(files)
patterns = self._get_platform_patterns(
self.exclude_package_data,
package,
src_dir,
)
bad = set(
item
for pattern in globs
for item in fnmatch.filter(
files,
os.path.join(src_dir, convert_path(pattern)),
)
match_groups = (
fnmatch.filter(files, pattern)
for pattern in patterns
)
seen = collections.defaultdict(itertools.count)
return [
# flatten the groups of matches into an iterable of matches
matches = itertools.chain.from_iterable(match_groups)
bad = set(matches)
keepers = (
fn
for fn in files
if fn not in bad
# ditch dupes
and not next(seen[fn])
]
)
# ditch dupes
return list(_unique_everseen(keepers))
@staticmethod
def _get_platform_patterns(spec, package, src_dir):
"""
yield platfrom-specific path patterns (suitable for glob
or fn_match) from a glob-based spec (such as
self.package_data or self.exclude_package_data)
matching package in src_dir.
"""
raw_patterns = itertools.chain(
spec.get('', []),
spec.get(package, []),
)
return (
# Each pattern has to be converted to a platform-specific path
os.path.join(src_dir, convert_path(pattern))
for pattern in raw_patterns
)
# from Python docs
def _unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
def assert_relative(path):
......
......@@ -32,7 +32,6 @@ import zipfile
import re
import stat
import random
import platform
import textwrap
import warnings
import site
......@@ -2203,8 +2202,6 @@ def get_win_launcher(type):
Returns the executable as a byte string.
"""
launcher_fn = '%s.exe' % type
if platform.machine().lower() == 'arm':
launcher_fn = launcher_fn.replace(".", "-arm.")
if is_64bit():
launcher_fn = launcher_fn.replace(".", "-64.")
else:
......
......@@ -52,8 +52,10 @@ class egg_info(Command):
]
boolean_options = ['tag-date', 'tag-svn-revision']
negative_opt = {'no-svn-revision': 'tag-svn-revision',
'no-date': 'tag-date'}
negative_opt = {
'no-svn-revision': 'tag-svn-revision',
'no-date': 'tag-date',
}
def initialize_options(self):
self.egg_name = None
......@@ -197,6 +199,10 @@ class egg_info(Command):
if self.tag_build:
version += self.tag_build
if self.tag_svn_revision:
warnings.warn(
"tag_svn_revision is deprecated and will not be honored "
"in a future release"
)
version += '-r%s' % self.get_svn_revision()
if self.tag_date:
version += time.strftime("-%Y%m%d")
......
......@@ -179,7 +179,7 @@ class sdist(orig.sdist):
distribution.
"""
log.info("reading manifest file '%s'", self.manifest)
manifest = open(self.manifest, 'rbU')
manifest = open(self.manifest, 'rb')
for line in manifest:
# The manifest must contain UTF-8. See #303.
if six.PY3:
......
import sys
import contextlib
from distutils.errors import DistutilsOptionError
from unittest import TestLoader
import sys
from setuptools.extern import six
from setuptools.extern.six.moves import map
......@@ -102,6 +103,14 @@ class test(Command):
yield self.test_suite
def with_project_on_sys_path(self, func):
"""
Backward compatibility for project_on_sys_path context.
"""
with self.project_on_sys_path():
func()
@contextlib.contextmanager
def project_on_sys_path(self):
with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False)
if with_2to3:
......@@ -137,7 +146,7 @@ class test(Command):
working_set.__init__()
add_activation_listener(lambda dist: dist.activate())
require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version))
func()
yield
finally:
sys.path[:] = old_path
sys.modules.clear()
......@@ -154,9 +163,11 @@ class test(Command):
cmd = ' '.join(self._argv)
if self.dry_run:
self.announce('skipping "%s" (dry run)' % cmd)
else:
self.announce('running "%s"' % cmd)
self.with_project_on_sys_path(self.run_tests)
return
self.announce('running "%s"' % cmd)
with self.project_on_sys_path():
self.run_tests()
def run_tests(self):
# Purge modules under test from sys.modules. The test loader will
......
......@@ -13,6 +13,8 @@ import socket
import zipfile
import tempfile
import shutil
import itertools
import functools
from setuptools.extern import six
from setuptools.extern.six.moves import http_client, urllib
......@@ -21,15 +23,9 @@ from pkg_resources import iter_entry_points
from .upload import upload
errors = 'surrogateescape' if six.PY3 else 'strict'
# This is not just a replacement for byte literals
# but works as a general purpose encoder
def b(s, encoding='utf-8'):
if isinstance(s, six.text_type):
return s.encode(encoding, errors)
return s
def _encode(s):
errors = 'surrogateescape' if six.PY3 else 'strict'
return s.encode('utf-8', errors)
class upload_docs(upload):
......@@ -101,10 +97,48 @@ class upload_docs(upload):
finally:
shutil.rmtree(tmp_dir)
@staticmethod
def _build_part(item, sep_boundary):
key, values = item
title = '\nContent-Disposition: form-data; name="%s"' % key
# handle multiple entries for the same name
if not isinstance(values, list):
values = [values]
for value in values:
if type(value) is tuple:
title += '; filename="%s"' % value[0]
value = value[1]
else:
value = _encode(value)
yield sep_boundary
yield _encode(title)
yield b"\n\n"
yield value
if value and value[-1:] == b'\r':
yield b'\n' # write an extra newline (lurve Macs)
@classmethod
def _build_multipart(cls, data):
"""
Build up the MIME payload for the POST data
"""
boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
sep_boundary = b'\n--' + boundary
end_boundary = sep_boundary + b'--'
end_items = end_boundary, b"\n",
builder = functools.partial(
cls._build_part,
sep_boundary=sep_boundary,
)
part_groups = map(builder, data.items())
parts = itertools.chain.from_iterable(part_groups)
body_items = itertools.chain(parts, end_items)
content_type = 'multipart/form-data; boundary=%s' % boundary
return b''.join(body_items), content_type
def upload_file(self, filename):
f = open(filename, 'rb')
content = f.read()
f.close()
with open(filename, 'rb') as f:
content = f.read()
meta = self.distribution.metadata
data = {
':action': 'doc_upload',
......@@ -112,37 +146,13 @@ class upload_docs(upload):
'content': (os.path.basename(filename), content),
}
# set up the authentication
credentials = b(self.username + ':' + self.password)
credentials = _encode(self.username + ':' + self.password)
credentials = standard_b64encode(credentials)
if six.PY3:
credentials = credentials.decode('ascii')
auth = "Basic " + credentials
# Build up the MIME payload for the POST data
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
sep_boundary = b('\n--') + b(boundary)
end_boundary = sep_boundary + b('--')
body = []
for key, values in six.iteritems(data):
title = '\nContent-Disposition: form-data; name="%s"' % key
# handle multiple entries for the same name
if not isinstance(values, list):
values = [values]
for value in values:
if type(value) is tuple:
title += '; filename="%s"' % value[0]
value = value[1]
else:
value = b(value)
body.append(sep_boundary)
body.append(b(title))
body.append(b("\n\n"))
body.append(value)
if value and value[-1:] == b('\r'):
body.append(b('\n')) # write an extra newline (lurve Macs)
body.append(end_boundary)
body.append(b("\n"))
body = b('').join(body)
body, ct = self._build_multipart(data)
self.announce("Submitting documentation to %s" % (self.repository),
log.INFO)
......@@ -164,7 +174,7 @@ class upload_docs(upload):
try:
conn.connect()
conn.putrequest("POST", url)
content_type = 'multipart/form-data; boundary=%s' % boundary
content_type = ct
conn.putheader('Content-type', content_type)
conn.putheader('Content-length', str(len(body)))
conn.putheader('Authorization', auth)
......
......@@ -17,6 +17,7 @@ except ImportError:
from setuptools.extern import six
from setuptools.extern.six.moves import urllib, http_client, configparser, map
import setuptools
from pkg_resources import (
CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST,
require, Environment, find_distributions, safe_name, safe_version,
......@@ -46,6 +47,11 @@ __all__ = [
_SOCKET_TIMEOUT = 15
_tmpl = "setuptools/{setuptools.__version__} Python-urllib/{py_major}"
user_agent = _tmpl.format(py_major=sys.version[:3], **globals())
def parse_bdist_wininst(name):
"""Return (base,pyversion) or (None,None) for possible .exe name"""
......@@ -202,9 +208,6 @@ def find_external_links(url, page):
if match:
yield urllib.parse.urljoin(url, htmldecode(match.group(1)))
user_agent = "Python-urllib/%s setuptools/%s" % (
sys.version[:3], require('setuptools')[0].version
)
class ContentChecker(object):
"""
......
import os
import pytest
from setuptools.dist import Distribution
@pytest.yield_fixture
def tmpdir_as_cwd(tmpdir):
with tmpdir.as_cwd():
yield tmpdir
def test_directories_in_package_data_glob(tmpdir_as_cwd):
"""
Directories matching the glob in package_data should
not be included in the package data.
Regression test for #261.
"""
dist = Distribution(dict(
script_name='setup.py',
script_args=['build_py'],
packages=[''],
name='foo',
package_data={'': ['path/*']},
))
os.makedirs('path/subpath')
#with contexts.quiet():
dist.parse_command_line()
dist.run_commands()
......@@ -57,3 +57,15 @@ class TestUploadDocsTest:
with contextlib.closing(zipfile.ZipFile(tmp_file)) as zip_file:
assert zip_file.namelist() == ['index.html']
def test_build_multipart(self):
data = dict(
a="foo",
b="bar",
file=('file.txt', b'content'),
)
body, content_type = upload_docs._build_multipart(data)
assert 'form-data' in content_type
assert isinstance(body, bytes)
assert b'foo' in body
assert b'content' in body
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment