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 ...@@ -264,3 +264,16 @@ ddd3f81eb9e0860bf95c380c50a72c52a215231f v21.0.0
40b8fac6db119aca9c462993d01908492769fc4f v21.2.0 40b8fac6db119aca9c462993d01908492769fc4f v21.2.0
40b8fac6db119aca9c462993d01908492769fc4f v21.2.0 40b8fac6db119aca9c462993d01908492769fc4f v21.2.0
9959424676a4aac1c14e430ff6f4210fdb0442d9 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: ...@@ -26,6 +26,8 @@ before_deploy:
- export SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES=1 - export SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES=1
deploy: deploy:
provider: pypi provider: pypi
# Also update server in setup.cfg
server: https://upload.pypi.io/legacy/
on: on:
tags: true tags: true
all_branches: true all_branches: true
......
...@@ -10,6 +10,83 @@ Next ...@@ -10,6 +10,83 @@ Next
* Renamed ``setuptools.msvc9_support`` to * Renamed ``setuptools.msvc9_support`` to
``setuptools.msvc``. ``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 v21.2.0
------- -------
...@@ -111,7 +188,7 @@ v20.6.0 ...@@ -111,7 +188,7 @@ v20.6.0
20.5 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, in requirements in install_requires, setup_requires,
tests_require as well as adding a test for the existing tests_require as well as adding a test for the existing
extra_requires machinery. extra_requires machinery.
......
...@@ -5,7 +5,8 @@ Installing and Using Setuptools ...@@ -5,7 +5,8 @@ Installing and Using Setuptools
.. contents:: **Table of Contents** .. 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 Installation Instructions
...@@ -36,6 +37,10 @@ Powershell command. Start up Powershell and paste this command:: ...@@ -36,6 +37,10 @@ Powershell command. Start up Powershell and paste this command::
> (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python - > (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 You must start the Powershell with Administrative privileges or you may choose
to install a user-local installation:: to install a user-local installation::
...@@ -177,10 +182,10 @@ them there, so this reference list can be updated. If you have working, ...@@ -177,10 +182,10 @@ them there, so this reference list can be updated. If you have working,
the `setuptools bug tracker`_. the `setuptools bug tracker`_.
.. _setuptools bug tracker: https://github.com/pypa/setuptools/issues .. _setuptools bug tracker: https://github.com/pypa/setuptools/issues
.. _The Internal Structure of Python Eggs: https://pythonhosted.org/setuptools/formats.html .. _The Internal Structure of Python Eggs: https://setuptools.readthedocs.io/en/latest/formats.html
.. _The setuptools Developer's Guide: https://pythonhosted.org/setuptools/setuptools.html .. _The setuptools Developer's Guide: https://setuptools.readthedocs.io/en/latest/developer-guide.html
.. _The pkg_resources API reference: https://pythonhosted.org/setuptools/pkg_resources.html .. _The pkg_resources API reference: https://setuptools.readthedocs.io/en/latest/pkg_resources.html
.. _The EasyInstall user's guide and reference manual: https://pythonhosted.org/setuptools/easy_install.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/ .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/
......
...@@ -200,7 +200,7 @@ latex_documents = [ ...@@ -200,7 +200,7 @@ latex_documents = [
#latex_use_modindex = True #latex_use_modindex = True
link_files = { link_files = {
'CHANGES.rst': dict( '../CHANGES.rst': dict(
using=dict( using=dict(
BB='https://bitbucket.org', BB='https://bitbucket.org',
GH='https://github.com', GH='https://github.com',
......
...@@ -677,7 +677,7 @@ locations, build options, etc., EasyInstall will respect your existing settings ...@@ -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. 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 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 Notice that ``easy_install`` will use the ``setup.cfg`` from the current
working directory only if it was triggered from ``setup.py`` through the 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 ...@@ -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 a quick example of converting code that uses ``__file__`` to use
``pkg_resources`` instead. ``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 .. _Accessing Package Resources: http://peak.telecommunity.com/DevCenter/PythonEggs#accessing-package-resources
......
...@@ -35,21 +35,5 @@ if "%ERRORLEVEL%"=="0" ( ...@@ -35,21 +35,5 @@ if "%ERRORLEVEL%"=="0" (
echo Windows SDK 6.1 not found to build Windows 64-bit version 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% set PATH=%PATH_OLD%
[bumpversion] [bumpversion]
current_version = 21.2.0 current_version = 23.2.1
commit = True commit = True
tag = True tag = True
...@@ -9,18 +9,13 @@ tag_date = 1 ...@@ -9,18 +9,13 @@ tag_date = 1
[aliases] [aliases]
clean_egg_info = egg_info -RDb '' 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 source = register sdist binary
binary = bdist_egg upload --show-response binary = bdist_egg upload --show-response
test = pytest test = pytest
[build_sphinx] [upload]
source-dir = docs/ repository = https://upload.pypi.io/legacy/
build-dir = docs/build
all_files = 1
[upload_docs]
upload-dir = docs/build/html
[sdist] [sdist]
formats = gztar zip formats = gztar zip
......
...@@ -61,14 +61,12 @@ if (sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt')) \ ...@@ -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) needs_pytest = set(['ptr', 'pytest', 'test']).intersection(sys.argv)
pytest_runner = ['pytest-runner'] if needs_pytest else [] 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) needs_wheel = set(['release', 'bdist_wheel']).intersection(sys.argv)
wheel = ['wheel'] if needs_wheel else [] wheel = ['wheel'] if needs_wheel else []
setup_params = dict( setup_params = dict(
name="setuptools", name="setuptools",
version="21.2.0", version="23.2.1",
description="Easily download, build, install, upgrade, and uninstall " description="Easily download, build, install, upgrade, and uninstall "
"Python packages", "Python packages",
author="Python Packaging Authority", author="Python Packaging Authority",
...@@ -158,7 +156,7 @@ setup_params = dict( ...@@ -158,7 +156,7 @@ setup_params = dict(
'pytest>=2.8', 'pytest>=2.8',
] + (['mock'] if sys.version_info[:2] < (3, 3) else []), ] + (['mock'] if sys.version_info[:2] < (3, 3) else []),
setup_requires=[ setup_requires=[
] + sphinx + pytest_runner + wheel, ] + pytest_runner + wheel,
) )
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -6,10 +6,10 @@ import fnmatch ...@@ -6,10 +6,10 @@ import fnmatch
import textwrap import textwrap
import io import io
import distutils.errors import distutils.errors
import collections
import itertools import itertools
from setuptools.extern.six.moves import map from setuptools.extern import six
from setuptools.extern.six.moves import map, filter, filterfalse
try: try:
from setuptools.lib2to3_ex import Mixin2to3 from setuptools.lib2to3_ex import Mixin2to3
...@@ -67,6 +67,9 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -67,6 +67,9 @@ class build_py(orig.build_py, Mixin2to3):
return orig.build_py.__getattr__(self, attr) return orig.build_py.__getattr__(self, attr)
def build_module(self, module, module_file, package): 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, outfile, copied = orig.build_py.build_module(self, module, module_file,
package) package)
if copied: if copied:
...@@ -94,12 +97,19 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -94,12 +97,19 @@ class build_py(orig.build_py, Mixin2to3):
def find_data_files(self, package, src_dir): def find_data_files(self, package, src_dir):
"""Return filenames for package's data files in 'src_dir'""" """Return filenames for package's data files in 'src_dir'"""
globs = (self.package_data.get('', []) patterns = self._get_platform_patterns(
+ self.package_data.get(package, [])) self.package_data,
files = self.manifest_files.get(package, [])[:] package,
for pattern in globs: src_dir,
# Each pattern has to be converted to a platform-specific path )
files.extend(glob(os.path.join(src_dir, convert_path(pattern)))) 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) return self.exclude_data_files(package, src_dir, files)
def build_package_data(self): def build_package_data(self):
...@@ -184,26 +194,63 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -184,26 +194,63 @@ class build_py(orig.build_py, Mixin2to3):
def exclude_data_files(self, package, src_dir, files): def exclude_data_files(self, package, src_dir, files):
"""Filter filenames for package's data files in 'src_dir'""" """Filter filenames for package's data files in 'src_dir'"""
globs = ( files = list(files)
self.exclude_package_data.get('', []) patterns = self._get_platform_patterns(
+ self.exclude_package_data.get(package, []) self.exclude_package_data,
package,
src_dir,
) )
bad = set( match_groups = (
item fnmatch.filter(files, pattern)
for pattern in globs for pattern in patterns
for item in fnmatch.filter(
files,
os.path.join(src_dir, convert_path(pattern)),
)
) )
seen = collections.defaultdict(itertools.count) # flatten the groups of matches into an iterable of matches
return [ matches = itertools.chain.from_iterable(match_groups)
bad = set(matches)
keepers = (
fn fn
for fn in files for fn in files
if fn not in bad 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): def assert_relative(path):
......
...@@ -32,7 +32,6 @@ import zipfile ...@@ -32,7 +32,6 @@ import zipfile
import re import re
import stat import stat
import random import random
import platform
import textwrap import textwrap
import warnings import warnings
import site import site
...@@ -2203,8 +2202,6 @@ def get_win_launcher(type): ...@@ -2203,8 +2202,6 @@ def get_win_launcher(type):
Returns the executable as a byte string. Returns the executable as a byte string.
""" """
launcher_fn = '%s.exe' % type launcher_fn = '%s.exe' % type
if platform.machine().lower() == 'arm':
launcher_fn = launcher_fn.replace(".", "-arm.")
if is_64bit(): if is_64bit():
launcher_fn = launcher_fn.replace(".", "-64.") launcher_fn = launcher_fn.replace(".", "-64.")
else: else:
......
...@@ -52,8 +52,10 @@ class egg_info(Command): ...@@ -52,8 +52,10 @@ class egg_info(Command):
] ]
boolean_options = ['tag-date', 'tag-svn-revision'] boolean_options = ['tag-date', 'tag-svn-revision']
negative_opt = {'no-svn-revision': 'tag-svn-revision', negative_opt = {
'no-date': 'tag-date'} 'no-svn-revision': 'tag-svn-revision',
'no-date': 'tag-date',
}
def initialize_options(self): def initialize_options(self):
self.egg_name = None self.egg_name = None
...@@ -197,6 +199,10 @@ class egg_info(Command): ...@@ -197,6 +199,10 @@ class egg_info(Command):
if self.tag_build: if self.tag_build:
version += self.tag_build version += self.tag_build
if self.tag_svn_revision: 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() version += '-r%s' % self.get_svn_revision()
if self.tag_date: if self.tag_date:
version += time.strftime("-%Y%m%d") version += time.strftime("-%Y%m%d")
......
...@@ -179,7 +179,7 @@ class sdist(orig.sdist): ...@@ -179,7 +179,7 @@ class sdist(orig.sdist):
distribution. distribution.
""" """
log.info("reading manifest file '%s'", self.manifest) log.info("reading manifest file '%s'", self.manifest)
manifest = open(self.manifest, 'rbU') manifest = open(self.manifest, 'rb')
for line in manifest: for line in manifest:
# The manifest must contain UTF-8. See #303. # The manifest must contain UTF-8. See #303.
if six.PY3: if six.PY3:
......
import sys
import contextlib
from distutils.errors import DistutilsOptionError from distutils.errors import DistutilsOptionError
from unittest import TestLoader from unittest import TestLoader
import sys
from setuptools.extern import six from setuptools.extern import six
from setuptools.extern.six.moves import map from setuptools.extern.six.moves import map
...@@ -102,6 +103,14 @@ class test(Command): ...@@ -102,6 +103,14 @@ class test(Command):
yield self.test_suite yield self.test_suite
def with_project_on_sys_path(self, func): 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) with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False)
if with_2to3: if with_2to3:
...@@ -137,7 +146,7 @@ class test(Command): ...@@ -137,7 +146,7 @@ class test(Command):
working_set.__init__() working_set.__init__()
add_activation_listener(lambda dist: dist.activate()) add_activation_listener(lambda dist: dist.activate())
require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version))
func() yield
finally: finally:
sys.path[:] = old_path sys.path[:] = old_path
sys.modules.clear() sys.modules.clear()
...@@ -154,9 +163,11 @@ class test(Command): ...@@ -154,9 +163,11 @@ class test(Command):
cmd = ' '.join(self._argv) cmd = ' '.join(self._argv)
if self.dry_run: if self.dry_run:
self.announce('skipping "%s" (dry run)' % cmd) self.announce('skipping "%s" (dry run)' % cmd)
else: return
self.announce('running "%s"' % cmd)
self.with_project_on_sys_path(self.run_tests) self.announce('running "%s"' % cmd)
with self.project_on_sys_path():
self.run_tests()
def run_tests(self): def run_tests(self):
# Purge modules under test from sys.modules. The test loader will # Purge modules under test from sys.modules. The test loader will
......
...@@ -13,6 +13,8 @@ import socket ...@@ -13,6 +13,8 @@ import socket
import zipfile import zipfile
import tempfile import tempfile
import shutil import shutil
import itertools
import functools
from setuptools.extern import six from setuptools.extern import six
from setuptools.extern.six.moves import http_client, urllib from setuptools.extern.six.moves import http_client, urllib
...@@ -21,15 +23,9 @@ from pkg_resources import iter_entry_points ...@@ -21,15 +23,9 @@ from pkg_resources import iter_entry_points
from .upload import upload from .upload import upload
errors = 'surrogateescape' if six.PY3 else 'strict' def _encode(s):
errors = 'surrogateescape' if six.PY3 else 'strict'
return s.encode('utf-8', errors)
# 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
class upload_docs(upload): class upload_docs(upload):
...@@ -101,10 +97,48 @@ class upload_docs(upload): ...@@ -101,10 +97,48 @@ class upload_docs(upload):
finally: finally:
shutil.rmtree(tmp_dir) 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): def upload_file(self, filename):
f = open(filename, 'rb') with open(filename, 'rb') as f:
content = f.read() content = f.read()
f.close()
meta = self.distribution.metadata meta = self.distribution.metadata
data = { data = {
':action': 'doc_upload', ':action': 'doc_upload',
...@@ -112,37 +146,13 @@ class upload_docs(upload): ...@@ -112,37 +146,13 @@ class upload_docs(upload):
'content': (os.path.basename(filename), content), 'content': (os.path.basename(filename), content),
} }
# set up the authentication # set up the authentication
credentials = b(self.username + ':' + self.password) credentials = _encode(self.username + ':' + self.password)
credentials = standard_b64encode(credentials) credentials = standard_b64encode(credentials)
if six.PY3: if six.PY3:
credentials = credentials.decode('ascii') credentials = credentials.decode('ascii')
auth = "Basic " + credentials auth = "Basic " + credentials
# Build up the MIME payload for the POST data body, ct = self._build_multipart(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)
self.announce("Submitting documentation to %s" % (self.repository), self.announce("Submitting documentation to %s" % (self.repository),
log.INFO) log.INFO)
...@@ -164,7 +174,7 @@ class upload_docs(upload): ...@@ -164,7 +174,7 @@ class upload_docs(upload):
try: try:
conn.connect() conn.connect()
conn.putrequest("POST", url) conn.putrequest("POST", url)
content_type = 'multipart/form-data; boundary=%s' % boundary content_type = ct
conn.putheader('Content-type', content_type) conn.putheader('Content-type', content_type)
conn.putheader('Content-length', str(len(body))) conn.putheader('Content-length', str(len(body)))
conn.putheader('Authorization', auth) conn.putheader('Authorization', auth)
......
...@@ -17,6 +17,7 @@ except ImportError: ...@@ -17,6 +17,7 @@ except ImportError:
from setuptools.extern import six from setuptools.extern import six
from setuptools.extern.six.moves import urllib, http_client, configparser, map from setuptools.extern.six.moves import urllib, http_client, configparser, map
import setuptools
from pkg_resources import ( from pkg_resources import (
CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST, CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST,
require, Environment, find_distributions, safe_name, safe_version, require, Environment, find_distributions, safe_name, safe_version,
...@@ -46,6 +47,11 @@ __all__ = [ ...@@ -46,6 +47,11 @@ __all__ = [
_SOCKET_TIMEOUT = 15 _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): def parse_bdist_wininst(name):
"""Return (base,pyversion) or (None,None) for possible .exe name""" """Return (base,pyversion) or (None,None) for possible .exe name"""
...@@ -202,9 +208,6 @@ def find_external_links(url, page): ...@@ -202,9 +208,6 @@ def find_external_links(url, page):
if match: if match:
yield urllib.parse.urljoin(url, htmldecode(match.group(1))) 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): 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: ...@@ -57,3 +57,15 @@ class TestUploadDocsTest:
with contextlib.closing(zipfile.ZipFile(tmp_file)) as zip_file: with contextlib.closing(zipfile.ZipFile(tmp_file)) as zip_file:
assert zip_file.namelist() == ['index.html'] 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