summaryrefslogtreecommitdiff
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/asyncio366.diff200
-rw-r--r--debian/patches/bdist-wininst-notfound.diff19
-rw-r--r--debian/patches/ctypes-arm.diff34
-rw-r--r--debian/patches/deb-locations.diff30
-rw-r--r--debian/patches/deb-setup.diff33
-rw-r--r--debian/patches/disable-sem-check.diff38
-rw-r--r--debian/patches/disable-some-tests.diff14
-rw-r--r--debian/patches/distutils-init.diff49
-rw-r--r--debian/patches/distutils-install-layout.diff278
-rw-r--r--debian/patches/distutils-link.diff24
-rw-r--r--debian/patches/distutils-sysconfig.diff45
-rw-r--r--debian/patches/doc-faq.dpatch52
-rw-r--r--debian/patches/ensurepip-disabled.diff87
-rw-r--r--debian/patches/ensurepip-wheels.diff131
-rw-r--r--debian/patches/ext-no-libpython-link.diff24
-rw-r--r--debian/patches/gdbm-import.diff12
-rw-r--r--debian/patches/git-updates.diff4
-rw-r--r--debian/patches/hurd-disable-nonworking-constants.diff38
-rw-r--r--debian/patches/issue21264.diff31
-rw-r--r--debian/patches/langpack-gettext.diff36
-rw-r--r--debian/patches/lib-argparse.diff22
-rw-r--r--debian/patches/lib2to3-no-pgen-caching.diff76
-rw-r--r--debian/patches/lib2to3-no-pickled-grammar.diff16
-rw-r--r--debian/patches/link-opt.diff26
-rw-r--r--debian/patches/link-timemodule.diff13
-rw-r--r--debian/patches/local-blurb.diff13
-rw-r--r--debian/patches/locale-module.diff19
-rw-r--r--debian/patches/lto-link-flags.diff22
-rw-r--r--debian/patches/makesetup-bashism.diff15
-rw-r--r--debian/patches/mangle-fstack-protector.diff26
-rw-r--r--debian/patches/mpdecimal-version.diff17
-rw-r--r--debian/patches/multiarch-extname.diff92
-rw-r--r--debian/patches/multiarch.diff136
-rw-r--r--debian/patches/no-large-file-support.diff18
-rw-r--r--debian/patches/platform-lsbrelease.diff85
-rw-r--r--debian/patches/profiled-build.diff23
-rw-r--r--debian/patches/pydoc-use-pager.diff15
-rw-r--r--debian/patches/pyhash.diff17
-rw-r--r--debian/patches/reproducible-buildinfo.diff15
-rw-r--r--debian/patches/series42
-rw-r--r--debian/patches/setup-modules.diff52
-rw-r--r--debian/patches/sysconfig-debian-schemes.diff67
-rw-r--r--debian/patches/sysconfigdata.diff76
-rw-r--r--debian/patches/tempfile-minimal.diff169
-rw-r--r--debian/patches/test-no-random-order.diff14
-rw-r--r--debian/patches/tkinter-import.diff18
46 files changed, 2283 insertions, 0 deletions
diff --git a/debian/patches/asyncio366.diff b/debian/patches/asyncio366.diff
new file mode 100644
index 0000000..cd7825b
--- /dev/null
+++ b/debian/patches/asyncio366.diff
@@ -0,0 +1,200 @@
+# DP: Fix callbacks race in SelectorLoop.sock_connect.
+# DP: https://github.com/python/asyncio/pull/366
+
+Index: b/Lib/asyncio/selector_events.py
+===================================================================
+--- a/Lib/asyncio/selector_events.py
++++ b/Lib/asyncio/selector_events.py
+@@ -382,6 +382,7 @@ class BaseSelectorEventLoop(base_events.
+ data = data[n:]
+ self.add_writer(fd, self._sock_sendall, fut, True, sock, data)
+
++ @coroutine
+ def sock_connect(self, sock, address):
+ """Connect to a remote socket at address.
+
+@@ -390,24 +391,16 @@ class BaseSelectorEventLoop(base_events.
+ if self._debug and sock.gettimeout() != 0:
+ raise ValueError("the socket must be non-blocking")
+
+- fut = self.create_future()
+- if hasattr(socket, 'AF_UNIX') and sock.family == socket.AF_UNIX:
+- self._sock_connect(fut, sock, address)
+- else:
++ if not hasattr(socket, 'AF_UNIX') or sock.family != socket.AF_UNIX:
+ resolved = base_events._ensure_resolved(
+ address, family=sock.family, proto=sock.proto, loop=self)
+- resolved.add_done_callback(
+- lambda resolved: self._on_resolved(fut, sock, resolved))
+-
+- return fut
+-
+- def _on_resolved(self, fut, sock, resolved):
+- try:
++ if not resolved.done():
++ yield from resolved
+ _, _, _, _, address = resolved.result()[0]
+- except Exception as exc:
+- fut.set_exception(exc)
+- else:
+- self._sock_connect(fut, sock, address)
++
++ fut = self.create_future()
++ self._sock_connect(fut, sock, address)
++ return (yield from fut)
+
+ def _sock_connect(self, fut, sock, address):
+ fd = sock.fileno()
+@@ -418,8 +411,8 @@ class BaseSelectorEventLoop(base_events.
+ # connection runs in background. We have to wait until the socket
+ # becomes writable to be notified when the connection succeed or
+ # fails.
+- fut.add_done_callback(functools.partial(self._sock_connect_done,
+- fd))
++ fut.add_done_callback(
++ functools.partial(self._sock_connect_done, fd))
+ self.add_writer(fd, self._sock_connect_cb, fut, sock, address)
+ except Exception as exc:
+ fut.set_exception(exc)
+Index: b/Lib/test/test_asyncio/test_selector_events.py
+===================================================================
+--- a/Lib/test/test_asyncio/test_selector_events.py
++++ b/Lib/test/test_asyncio/test_selector_events.py
+@@ -2,6 +2,8 @@
+
+ import errno
+ import socket
++import threading
++import time
+ import unittest
+ from unittest import mock
+ try:
+@@ -337,18 +339,6 @@ class BaseSelectorEventLoopTests(test_ut
+ (10, self.loop._sock_sendall, f, True, sock, b'data'),
+ self.loop.add_writer.call_args[0])
+
+- def test_sock_connect(self):
+- sock = test_utils.mock_nonblocking_socket()
+- self.loop._sock_connect = mock.Mock()
+-
+- f = self.loop.sock_connect(sock, ('127.0.0.1', 8080))
+- self.assertIsInstance(f, asyncio.Future)
+- self.loop._run_once()
+- future_in, sock_in, address_in = self.loop._sock_connect.call_args[0]
+- self.assertEqual(future_in, f)
+- self.assertEqual(sock_in, sock)
+- self.assertEqual(address_in, ('127.0.0.1', 8080))
+-
+ def test_sock_connect_timeout(self):
+ # asyncio issue #205: sock_connect() must unregister the socket on
+ # timeout error
+@@ -360,16 +350,16 @@ class BaseSelectorEventLoopTests(test_ut
+ sock.connect.side_effect = BlockingIOError
+
+ # first call to sock_connect() registers the socket
+- fut = self.loop.sock_connect(sock, ('127.0.0.1', 80))
++ fut = self.loop.create_task(
++ self.loop.sock_connect(sock, ('127.0.0.1', 80)))
+ self.loop._run_once()
+ self.assertTrue(sock.connect.called)
+ self.assertTrue(self.loop.add_writer.called)
+- self.assertEqual(len(fut._callbacks), 1)
+
+ # on timeout, the socket must be unregistered
+ sock.connect.reset_mock()
+- fut.set_exception(asyncio.TimeoutError)
+- with self.assertRaises(asyncio.TimeoutError):
++ fut.cancel()
++ with self.assertRaises(asyncio.CancelledError):
+ self.loop.run_until_complete(fut)
+ self.assertTrue(self.loop.remove_writer.called)
+
+@@ -1778,5 +1768,88 @@ class SelectorDatagramTransportTests(tes
+ exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
+
+
++class SelectorLoopFunctionalTests(unittest.TestCase):
++
++ def setUp(self):
++ self.loop = asyncio.new_event_loop()
++ asyncio.set_event_loop(None)
++
++ def tearDown(self):
++ self.loop.close()
++
++ @asyncio.coroutine
++ def recv_all(self, sock, nbytes):
++ buf = b''
++ while len(buf) < nbytes:
++ buf += yield from self.loop.sock_recv(sock, nbytes - len(buf))
++ return buf
++
++ def test_sock_connect_sock_write_race(self):
++ TIMEOUT = 3.0
++ PAYLOAD = b'DATA' * 1024 * 1024
++
++ class Server(threading.Thread):
++ def __init__(self, *args, srv_sock, **kwargs):
++ super().__init__(*args, **kwargs)
++ self.srv_sock = srv_sock
++
++ def run(self):
++ with self.srv_sock:
++ srv_sock.listen(100)
++
++ sock, addr = self.srv_sock.accept()
++ sock.settimeout(TIMEOUT)
++
++ with sock:
++ sock.sendall(b'helo')
++
++ buf = bytearray()
++ while len(buf) < len(PAYLOAD):
++ pack = sock.recv(1024 * 65)
++ if not pack:
++ break
++ buf.extend(pack)
++
++ @asyncio.coroutine
++ def client(addr):
++ sock = socket.socket()
++ with sock:
++ sock.setblocking(False)
++
++ started = time.monotonic()
++ while True:
++ if time.monotonic() - started > TIMEOUT:
++ self.fail('unable to connect to the socket')
++ return
++ try:
++ yield from self.loop.sock_connect(sock, addr)
++ except OSError:
++ yield from asyncio.sleep(0.05, loop=self.loop)
++ else:
++ break
++
++ # Give 'Server' thread a chance to accept and send b'helo'
++ time.sleep(0.1)
++
++ data = yield from self.recv_all(sock, 4)
++ self.assertEqual(data, b'helo')
++ yield from self.loop.sock_sendall(sock, PAYLOAD)
++
++ srv_sock = socket.socket()
++ srv_sock.settimeout(TIMEOUT)
++ srv_sock.bind(('127.0.0.1', 0))
++ srv_addr = srv_sock.getsockname()
++
++ srv = Server(srv_sock=srv_sock, daemon=True)
++ srv.start()
++
++ try:
++ self.loop.run_until_complete(
++ asyncio.wait_for(client(srv_addr), loop=self.loop,
++ timeout=TIMEOUT))
++ finally:
++ srv.join()
++
++
+ if __name__ == '__main__':
+ unittest.main()
diff --git a/debian/patches/bdist-wininst-notfound.diff b/debian/patches/bdist-wininst-notfound.diff
new file mode 100644
index 0000000..4705ad1
--- /dev/null
+++ b/debian/patches/bdist-wininst-notfound.diff
@@ -0,0 +1,19 @@
+# DP: suggest installation of the pythonX.Y-dev package, if bdist_wininst
+# DP: cannot find the wininst-* files.
+
+Index: b/Lib/distutils/command/bdist_wininst.py
+===================================================================
+--- a/Lib/distutils/command/bdist_wininst.py
++++ b/Lib/distutils/command/bdist_wininst.py
+@@ -354,7 +354,10 @@ class bdist_wininst(Command):
+ sfix = ''
+
+ filename = os.path.join(directory, "wininst-%.1f%s.exe" % (bv, sfix))
+- f = open(filename, "rb")
++ try:
++ f = open(filename, "rb")
++ except IOError as e:
++ raise DistutilsFileError(str(e) + ', %s not included in the Debian packages.' % filename)
+ try:
+ return f.read()
+ finally:
diff --git a/debian/patches/ctypes-arm.diff b/debian/patches/ctypes-arm.diff
new file mode 100644
index 0000000..a34f02e
--- /dev/null
+++ b/debian/patches/ctypes-arm.diff
@@ -0,0 +1,34 @@
+Index: b/Lib/ctypes/util.py
+===================================================================
+--- a/Lib/ctypes/util.py
++++ b/Lib/ctypes/util.py
+@@ -257,16 +257,27 @@ elif os.name == "posix":
+
+ def _findSoname_ldconfig(name):
+ import struct
++ # XXX this code assumes that we know all unames and that a single
++ # ABI is supported per uname; instead we should find what the
++ # ABI is (e.g. check ABI of current process) or simply ask libc
++ # to load the library for us
++ uname = os.uname()
++ # ARM has a variety of unames, e.g. armv7l
++ if uname.machine.startswith("arm"):
++ machine = "arm"
+ if struct.calcsize('l') == 4:
+- machine = os.uname().machine + '-32'
++ machine = uname.machine + '-32'
+ else:
+- machine = os.uname().machine + '-64'
++ machine = uname.machine + '-64'
+ mach_map = {
+ 'x86_64-64': 'libc6,x86-64',
+ 'ppc64-64': 'libc6,64bit',
+ 'sparc64-64': 'libc6,64bit',
+ 's390x-64': 'libc6,64bit',
+ 'ia64-64': 'libc6,IA-64',
++ # this actually breaks on biarch or multiarch as the first
++ # library wins; uname doesn't tell us which ABI we're using
++ 'arm-32': 'libc6(,hard-float)?',
+ }
+ abi_type = mach_map.get(machine, 'libc6')
+
diff --git a/debian/patches/deb-locations.diff b/debian/patches/deb-locations.diff
new file mode 100644
index 0000000..22e4c47
--- /dev/null
+++ b/debian/patches/deb-locations.diff
@@ -0,0 +1,30 @@
+# DP: adjust locations of directories to debian policy
+
+Index: b/Lib/pydoc.py
+===================================================================
+--- a/Lib/pydoc.py
++++ b/Lib/pydoc.py
+@@ -28,6 +28,10 @@ to a file named "<name>.html".
+
+ Module docs for core modules are assumed to be in
+
++ /usr/share/doc/pythonX.Y/html/library
++
++if the pythonX.Y-doc package is installed or in
++
+ https://docs.python.org/X.Y/library/
+
+ This can be overridden by setting the PYTHONDOCS environment variable
+Index: b/Misc/python.man
+===================================================================
+--- a/Misc/python.man
++++ b/Misc/python.man
+@@ -326,7 +326,7 @@ exception). Error messages are written
+ These are subject to difference depending on local installation
+ conventions; ${prefix} and ${exec_prefix} are installation-dependent
+ and should be interpreted as for GNU software; they may be the same.
+-The default for both is \fI/usr/local\fP.
++On Debian GNU/{Hurd,Linux} the default for both is \fI/usr\fP.
+ .IP \fI${exec_prefix}/bin/python\fP
+ Recommended location of the interpreter.
+ .PP
diff --git a/debian/patches/deb-setup.diff b/debian/patches/deb-setup.diff
new file mode 100644
index 0000000..08ce316
--- /dev/null
+++ b/debian/patches/deb-setup.diff
@@ -0,0 +1,33 @@
+# DP: Don't include /usr/local/include and /usr/local/lib as gcc search paths
+
+Index: b/setup.py
+===================================================================
+--- a/setup.py
++++ b/setup.py
+@@ -262,8 +262,10 @@ class PyBuildExt(build_ext):
+ # unfortunately, distutils doesn't let us provide separate C and C++
+ # compilers
+ if compiler is not None:
+- (ccshared,cflags) = sysconfig.get_config_vars('CCSHARED','CFLAGS')
+- args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags
++ (ccshared, cppflags, cflags) = \
++ sysconfig.get_config_vars('CCSHARED', 'CPPFLAGS', 'CFLAGS')
++ cppflags = ' '.join([f for f in cppflags.split() if not f.startswith('-I')])
++ args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cppflags + ' ' + cflags
+ self.compiler.set_executables(**args)
+
+ build_ext.build_extensions(self)
+@@ -487,12 +489,7 @@ class PyBuildExt(build_ext):
+ return ['m']
+
+ def detect_modules(self):
+- # Ensure that /usr/local is always used, but the local build
+- # directories (i.e. '.' and 'Include') must be first. See issue
+- # 10520.
+- if not cross_compiling:
+- add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
+- add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
++ # On Debian /usr/local is always used, so we don't include it twice
+ # only change this for cross builds for 3.3, issues on Mageia
+ if cross_compiling:
+ self.add_gcc_paths()
diff --git a/debian/patches/disable-sem-check.diff b/debian/patches/disable-sem-check.diff
new file mode 100644
index 0000000..6dfdae1
--- /dev/null
+++ b/debian/patches/disable-sem-check.diff
@@ -0,0 +1,38 @@
+# DP: Assume working semaphores, don't rely on running kernel for the check.
+
+Index: b/configure.ac
+===================================================================
+--- a/configure.ac
++++ b/configure.ac
+@@ -4382,8 +4382,13 @@ int main(void) {
+ AC_MSG_RESULT($ac_cv_posix_semaphores_enabled)
+ if test $ac_cv_posix_semaphores_enabled = no
+ then
+- AC_DEFINE(POSIX_SEMAPHORES_NOT_ENABLED, 1,
+- [Define if POSIX semaphores aren't enabled on your system])
++ case $ac_sys_system in
++ Linux*) # assume yes, see https://launchpad.net/bugs/630511
++ ;;
++ *)
++ AC_DEFINE(POSIX_SEMAPHORES_NOT_ENABLED, 1,
++ [Define if POSIX semaphores aren't enabled on your system])
++ esac
+ fi
+
+ # Multiprocessing check for broken sem_getvalue
+@@ -4418,8 +4423,13 @@ int main(void){
+ AC_MSG_RESULT($ac_cv_broken_sem_getvalue)
+ if test $ac_cv_broken_sem_getvalue = yes
+ then
+- AC_DEFINE(HAVE_BROKEN_SEM_GETVALUE, 1,
+- [define to 1 if your sem_getvalue is broken.])
++ case $ac_sys_system in
++ Linux*) # assume yes, see https://launchpad.net/bugs/630511
++ ;;
++ *)
++ AC_DEFINE(HAVE_BROKEN_SEM_GETVALUE, 1,
++ [define to 1 if your sem_getvalue is broken.])
++ esac
+ fi
+
+ # determine what size digit to use for Python's longs
diff --git a/debian/patches/disable-some-tests.diff b/debian/patches/disable-some-tests.diff
new file mode 100644
index 0000000..0adb144
--- /dev/null
+++ b/debian/patches/disable-some-tests.diff
@@ -0,0 +1,14 @@
+# DP: Disable some failing tests we are not interested in
+
+Index: b/Lib/distutils/tests/test_build_ext.py
+===================================================================
+--- a/Lib/distutils/tests/test_build_ext.py
++++ b/Lib/distutils/tests/test_build_ext.py
+@@ -99,6 +99,7 @@ class BuildExtTestCase(TempdirManager,
+ build_ext.USER_BASE = self.old_user_base
+ super(BuildExtTestCase, self).tearDown()
+
++ @unittest.skip('Skipping failing Solaris test')
+ def test_solaris_enable_shared(self):
+ dist = Distribution({'name': 'xx'})
+ cmd = self.build_ext(dist)
diff --git a/debian/patches/distutils-init.diff b/debian/patches/distutils-init.diff
new file mode 100644
index 0000000..9441640
--- /dev/null
+++ b/debian/patches/distutils-init.diff
@@ -0,0 +1,49 @@
+# DP: Use _sysconfigdata.py in distutils to initialize distutils
+
+Index: b/Lib/distutils/sysconfig.py
+===================================================================
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -435,38 +435,11 @@ _config_vars = None
+
+ def _init_posix():
+ """Initialize the module as appropriate for POSIX systems."""
+- g = {}
+- # load the installed Makefile:
+- try:
+- filename = get_makefile_filename()
+- parse_makefile(filename, g)
+- except OSError as msg:
+- my_msg = "invalid Python installation: unable to open %s" % filename
+- if hasattr(msg, "strerror"):
+- my_msg = my_msg + " (%s)" % msg.strerror
+-
+- raise DistutilsPlatformError(my_msg)
+-
+- # load the installed pyconfig.h:
+- try:
+- filename = get_config_h_filename()
+- with open(filename) as file:
+- parse_config_h(file, g)
+- except OSError as msg:
+- my_msg = "invalid Python installation: unable to open %s" % filename
+- if hasattr(msg, "strerror"):
+- my_msg = my_msg + " (%s)" % msg.strerror
+-
+- raise DistutilsPlatformError(my_msg)
+-
+- # On AIX, there are wrong paths to the linker scripts in the Makefile
+- # -- these paths are relative to the Python source, but when installed
+- # the scripts are in another directory.
+- if python_build:
+- g['LDSHARED'] = g['BLDSHARED']
+-
++ # _sysconfigdata is generated at build time, see the sysconfig module
++ from _sysconfigdata import build_time_vars
+ global _config_vars
+- _config_vars = g
++ _config_vars = {}
++ _config_vars.update(build_time_vars)
+
+
+ def _init_nt():
diff --git a/debian/patches/distutils-install-layout.diff b/debian/patches/distutils-install-layout.diff
new file mode 100644
index 0000000..caa4060
--- /dev/null
+++ b/debian/patches/distutils-install-layout.diff
@@ -0,0 +1,278 @@
+# DP: distutils: Add an option --install-layout=deb, which
+# DP: - installs into $prefix/dist-packages instead of $prefix/site-packages.
+# DP: - doesn't encode the python version into the egg name.
+
+Index: b/Lib/distutils/command/install_egg_info.py
+===================================================================
+--- a/Lib/distutils/command/install_egg_info.py
++++ b/Lib/distutils/command/install_egg_info.py
+@@ -14,18 +14,38 @@ class install_egg_info(Command):
+ description = "Install package's PKG-INFO metadata as an .egg-info file"
+ user_options = [
+ ('install-dir=', 'd', "directory to install to"),
++ ('install-layout', None, "custom installation layout"),
+ ]
+
+ def initialize_options(self):
+ self.install_dir = None
++ self.install_layout = None
++ self.prefix_option = None
+
+ def finalize_options(self):
+ self.set_undefined_options('install_lib',('install_dir','install_dir'))
+- basename = "%s-%s-py%s.egg-info" % (
+- to_filename(safe_name(self.distribution.get_name())),
+- to_filename(safe_version(self.distribution.get_version())),
+- sys.version[:3]
+- )
++ self.set_undefined_options('install',('install_layout','install_layout'))
++ self.set_undefined_options('install',('prefix_option','prefix_option'))
++ if self.install_layout:
++ if not self.install_layout.lower() in ['deb', 'unix']:
++ raise DistutilsOptionError(
++ "unknown value for --install-layout")
++ no_pyver = (self.install_layout.lower() == 'deb')
++ elif self.prefix_option:
++ no_pyver = False
++ else:
++ no_pyver = True
++ if no_pyver:
++ basename = "%s-%s.egg-info" % (
++ to_filename(safe_name(self.distribution.get_name())),
++ to_filename(safe_version(self.distribution.get_version()))
++ )
++ else:
++ basename = "%s-%s-py%s.egg-info" % (
++ to_filename(safe_name(self.distribution.get_name())),
++ to_filename(safe_version(self.distribution.get_version())),
++ sys.version[:3]
++ )
+ self.target = os.path.join(self.install_dir, basename)
+ self.outputs = [self.target]
+
+Index: b/Lib/distutils/command/install.py
+===================================================================
+--- a/Lib/distutils/command/install.py
++++ b/Lib/distutils/command/install.py
+@@ -35,6 +35,20 @@ INSTALL_SCHEMES = {
+ 'scripts': '$base/bin',
+ 'data' : '$base',
+ },
++ 'unix_local': {
++ 'purelib': '$base/local/lib/python$py_version_short/dist-packages',
++ 'platlib': '$platbase/local/lib/python$py_version_short/dist-packages',
++ 'headers': '$base/local/include/python$py_version_short/$dist_name',
++ 'scripts': '$base/local/bin',
++ 'data' : '$base/local',
++ },
++ 'deb_system': {
++ 'purelib': '$base/lib/python3/dist-packages',
++ 'platlib': '$platbase/lib/python3/dist-packages',
++ 'headers': '$base/include/python$py_version_short/$dist_name',
++ 'scripts': '$base/bin',
++ 'data' : '$base',
++ },
+ 'unix_home': {
+ 'purelib': '$base/lib/python',
+ 'platlib': '$base/lib/python',
+@@ -131,6 +145,9 @@ class install(Command):
+
+ ('record=', None,
+ "filename in which to record list of installed files"),
++
++ ('install-layout=', None,
++ "installation layout to choose (known values: deb, unix)"),
+ ]
+
+ boolean_options = ['compile', 'force', 'skip-build']
+@@ -151,6 +168,7 @@ class install(Command):
+ self.exec_prefix = None
+ self.home = None
+ self.user = 0
++ self.prefix_option = None
+
+ # These select only the installation base; it's up to the user to
+ # specify the installation scheme (currently, that means supplying
+@@ -172,6 +190,9 @@ class install(Command):
+ self.install_userbase = USER_BASE
+ self.install_usersite = USER_SITE
+
++ # enable custom installation, known values: deb
++ self.install_layout = None
++
+ self.compile = None
+ self.optimize = None
+
+@@ -411,6 +432,7 @@ class install(Command):
+ self.install_base = self.install_platbase = self.home
+ self.select_scheme("unix_home")
+ else:
++ self.prefix_option = self.prefix
+ if self.prefix is None:
+ if self.exec_prefix is not None:
+ raise DistutilsOptionError(
+@@ -425,7 +447,26 @@ class install(Command):
+
+ self.install_base = self.prefix
+ self.install_platbase = self.exec_prefix
+- self.select_scheme("unix_prefix")
++ if self.install_layout:
++ if self.install_layout.lower() in ['deb']:
++ self.select_scheme("deb_system")
++ elif self.install_layout.lower() in ['unix']:
++ self.select_scheme("unix_prefix")
++ else:
++ raise DistutilsOptionError(
++ "unknown value for --install-layout")
++ elif ((self.prefix_option and
++ os.path.normpath(self.prefix) != '/usr/local')
++ or sys.base_prefix != sys.prefix
++ or 'PYTHONUSERBASE' in os.environ
++ or 'VIRTUAL_ENV' in os.environ
++ or 'real_prefix' in sys.__dict__):
++ self.select_scheme("unix_prefix")
++ else:
++ if os.path.normpath(self.prefix) == '/usr/local':
++ self.prefix = self.exec_prefix = '/usr'
++ self.install_base = self.install_platbase = '/usr'
++ self.select_scheme("unix_local")
+
+ def finalize_other(self):
+ """Finalizes options for non-posix platforms"""
+Index: b/Lib/distutils/sysconfig.py
+===================================================================
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -122,6 +122,7 @@ def get_python_lib(plat_specific=0, stan
+ If 'prefix' is supplied, use it instead of sys.base_prefix or
+ sys.base_exec_prefix -- i.e., ignore 'plat_specific'.
+ """
++ is_default_prefix = not prefix or os.path.normpath(prefix) in ('/usr', '/usr/local')
+ if prefix is None:
+ if standard_lib:
+ prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX
+@@ -133,6 +134,12 @@ def get_python_lib(plat_specific=0, stan
+ "lib", "python" + get_python_version())
+ if standard_lib:
+ return libpython
++ elif (is_default_prefix and
++ 'PYTHONUSERBASE' not in os.environ and
++ 'VIRTUAL_ENV' not in os.environ and
++ 'real_prefix' not in sys.__dict__ and
++ sys.prefix == sys.base_prefix):
++ return os.path.join(prefix, "lib", "python3", "dist-packages")
+ else:
+ return os.path.join(libpython, "site-packages")
+ elif os.name == "nt":
+Index: b/Lib/site.py
+===================================================================
+--- a/Lib/site.py
++++ b/Lib/site.py
+@@ -7,12 +7,18 @@
+ This will append site-specific paths to the module search path. On
+ Unix (including Mac OSX), it starts with sys.prefix and
+ sys.exec_prefix (if different) and appends
+-lib/python<version>/site-packages.
++lib/python3/dist-packages.
+ On other platforms (such as Windows), it tries each of the
+ prefixes directly, as well as with lib/site-packages appended. The
+ resulting directories, if they exist, are appended to sys.path, and
+ also inspected for path configuration files.
+
++For Debian and derivatives, this sys.path is augmented with directories
++for packages distributed within the distribution. Local addons go
++into /usr/local/lib/python<version>/dist-packages, Debian addons
++install into /usr/lib/python3/dist-packages.
++/usr/lib/python<version>/site-packages is not used.
++
+ If a file named "pyvenv.cfg" exists one directory above sys.executable,
+ sys.prefix and sys.exec_prefix are set to that directory and
+ it is also checked for site-packages (sys.base_prefix and
+@@ -303,9 +309,20 @@ def getsitepackages(prefixes=None):
+ seen.add(prefix)
+
+ if os.sep == '/':
++ if 'VIRTUAL_ENV' in os.environ or sys.base_prefix != sys.prefix:
++ sitepackages.append(os.path.join(prefix, "lib",
++ "python" + sys.version[:3],
++ "site-packages"))
++ sitepackages.append(os.path.join(prefix, "local/lib",
++ "python" + sys.version[:3],
++ "dist-packages"))
++ sitepackages.append(os.path.join(prefix, "lib",
++ "python3",
++ "dist-packages"))
++ # this one is deprecated for Debian
+ sitepackages.append(os.path.join(prefix, "lib",
+- "python" + sys.version[:3],
+- "site-packages"))
++ "python" + sys.version[:3],
++ "dist-packages"))
+ else:
+ sitepackages.append(prefix)
+ sitepackages.append(os.path.join(prefix, "lib", "site-packages"))
+Index: b/Lib/test/test_site.py
+===================================================================
+--- a/Lib/test/test_site.py
++++ b/Lib/test/test_site.py
+@@ -261,9 +261,10 @@ class HelperFunctionsTests(unittest.Test
+ self.assertEqual(dirs[1], wanted)
+ elif os.sep == '/':
+ # OS X non-framwework builds, Linux, FreeBSD, etc
+- self.assertEqual(len(dirs), 1)
+- wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3],
+- 'site-packages')
++ self.assertEqual(len(dirs), 3)
++ wanted = os.path.join('xoxo', 'local', 'lib',
++ 'python' + sys.version[:3],
++ 'dist-packages')
+ self.assertEqual(dirs[0], wanted)
+ else:
+ # other platforms
+Index: b/Lib/distutils/tests/test_bdist_dumb.py
+===================================================================
+--- a/Lib/distutils/tests/test_bdist_dumb.py
++++ b/Lib/distutils/tests/test_bdist_dumb.py
+@@ -85,7 +85,7 @@ class BuildDumbTestCase(support.TempdirM
+ fp.close()
+
+ contents = sorted(os.path.basename(fn) for fn in contents)
+- wanted = ['foo-0.1-py%s.%s.egg-info' % sys.version_info[:2], 'foo.py']
++ wanted = ['foo-0.1.egg-info', 'foo.py']
+ if not sys.dont_write_bytecode:
+ wanted.append('foo.%s.pyc' % sys.implementation.cache_tag)
+ self.assertEqual(contents, sorted(wanted))
+Index: b/Lib/distutils/tests/test_install.py
+===================================================================
+--- a/Lib/distutils/tests/test_install.py
++++ b/Lib/distutils/tests/test_install.py
+@@ -192,7 +192,7 @@ class InstallTestCase(support.TempdirMan
+ found = [os.path.basename(line) for line in content.splitlines()]
+ expected = ['hello.py', 'hello.%s.pyc' % sys.implementation.cache_tag,
+ 'sayhi',
+- 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]]
++ 'UNKNOWN-0.0.0.egg-info']
+ self.assertEqual(found, expected)
+
+ def test_record_extensions(self):
+@@ -222,7 +222,7 @@ class InstallTestCase(support.TempdirMan
+
+ found = [os.path.basename(line) for line in content.splitlines()]
+ expected = [_make_ext_name('xx'),
+- 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]]
++ 'UNKNOWN-0.0.0.egg-info']
+ self.assertEqual(found, expected)
+
+ def test_debug_mode(self):
+Index: b/Lib/pydoc.py
+===================================================================
+--- a/Lib/pydoc.py
++++ b/Lib/pydoc.py
+@@ -410,6 +410,7 @@ class Doc:
+ 'marshal', 'posix', 'signal', 'sys',
+ '_thread', 'zipimport') or
+ (file.startswith(basedir) and
++ not file.startswith(os.path.join(basedir, 'dist-packages')) and
+ not file.startswith(os.path.join(basedir, 'site-packages')))) and
+ object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
+ if docloc.startswith(("http://", "https://")):
diff --git a/debian/patches/distutils-link.diff b/debian/patches/distutils-link.diff
new file mode 100644
index 0000000..b8ad3cf
--- /dev/null
+++ b/debian/patches/distutils-link.diff
@@ -0,0 +1,24 @@
+# DP: Don't add standard library dirs to library_dirs and runtime_library_dirs.
+
+Index: b/Lib/distutils/unixccompiler.py
+===================================================================
+--- a/Lib/distutils/unixccompiler.py
++++ b/Lib/distutils/unixccompiler.py
+@@ -155,6 +155,17 @@ class UnixCCompiler(CCompiler):
+ runtime_library_dirs)
+ libraries, library_dirs, runtime_library_dirs = fixed_args
+
++ # filter out standard library paths, which are not explicitely needed
++ # for linking
++ system_libdirs = ['/lib', '/lib64', '/usr/lib', '/usr/lib64']
++ multiarch = sysconfig.get_config_var("MULTIARCH")
++ if multiarch:
++ system_libdirs.extend(['/lib/%s' % multiarch, '/usr/lib/%s' % multiarch])
++ library_dirs = [dir for dir in library_dirs
++ if not dir in system_libdirs]
++ runtime_library_dirs = [dir for dir in runtime_library_dirs
++ if not dir in system_libdirs]
++
+ lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs,
+ libraries)
+ if not isinstance(output_dir, (str, type(None))):
diff --git a/debian/patches/distutils-sysconfig.diff b/debian/patches/distutils-sysconfig.diff
new file mode 100644
index 0000000..c12e6b3
--- /dev/null
+++ b/debian/patches/distutils-sysconfig.diff
@@ -0,0 +1,45 @@
+# DP: Get CONFIGURE_CFLAGS, CONFIGURE_CPPFLAGS, CONFIGURE_LDFLAGS from
+# DP: the python build, when CFLAGS, CPPFLAGS, LDSHARED) are not set
+# DP: in the environment.
+
+Index: b/Lib/distutils/sysconfig.py
+===================================================================
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -177,9 +177,11 @@ def customize_compiler(compiler):
+ _osx_support.customize_compiler(_config_vars)
+ _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
+
+- (cc, cxx, opt, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
++ (cc, cxx, opt, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags,
++ configure_cppflags, configure_cflags, configure_ldflags) = \
+ get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
+- 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++ 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS',
++ 'CONFIGURE_CPPFLAGS', 'CONFIGURE_CFLAGS', 'CONFIGURE_LDFLAGS')
+
+ if 'CC' in os.environ:
+ newcc = os.environ['CC']
+@@ -200,13 +202,22 @@ def customize_compiler(compiler):
+ cpp = cc + " -E" # not always
+ if 'LDFLAGS' in os.environ:
+ ldshared = ldshared + ' ' + os.environ['LDFLAGS']
++ elif configure_ldflags:
++ ldshared = ldshared + ' ' + configure_ldflags
+ if 'CFLAGS' in os.environ:
+ cflags = opt + ' ' + os.environ['CFLAGS']
+ ldshared = ldshared + ' ' + os.environ['CFLAGS']
++ elif configure_cflags:
++ cflags = opt + ' ' + configure_cflags
++ ldshared = ldshared + ' ' + configure_cflags
+ if 'CPPFLAGS' in os.environ:
+ cpp = cpp + ' ' + os.environ['CPPFLAGS']
+ cflags = cflags + ' ' + os.environ['CPPFLAGS']
+ ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
++ elif configure_cppflags:
++ cpp = cpp + ' ' + configure_cppflags
++ cflags = cflags + ' ' + configure_cppflags
++ ldshared = ldshared + ' ' + configure_cppflags
+ if 'AR' in os.environ:
+ ar = os.environ['AR']
+ if 'ARFLAGS' in os.environ:
diff --git a/debian/patches/doc-faq.dpatch b/debian/patches/doc-faq.dpatch
new file mode 100644
index 0000000..cf896e3
--- /dev/null
+++ b/debian/patches/doc-faq.dpatch
@@ -0,0 +1,52 @@
+#! /bin/sh -e
+
+# DP: Mention the FAQ on the documentation index page.
+
+dir=
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+ dir="$3/"
+elif [ $# -ne 1 ]; then
+ echo >&2 "usage: `basename $0`: -patch|-unpatch [-d <srcdir>]"
+ exit 1
+fi
+case "$1" in
+ -patch)
+ patch $pdir -f --no-backup-if-mismatch -p0 < $0
+ ;;
+ -unpatch)
+ patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
+ ;;
+ *)
+ echo >&2 "usage: `basename $0`: -patch|-unpatch [-d <srcdir>]"
+ exit 1
+esac
+exit 0
+
+--- Doc/html/index.html.in~ 2002-04-01 18:11:27.000000000 +0200
++++ Doc/html/index.html.in 2003-04-05 13:33:35.000000000 +0200
+@@ -123,6 +123,24 @@
+ </ul>
+ </td>
+ </tr>
++ <tr>
++ <td valign="baseline" class="left-column">
++ &nbsp;
++ <ul>
++ <li> <a href="../../python/FAQ.html" class="title"
++ >FAQ (local copy)</a>
++ <br>(python package must be installed)
++ </ul>
++ </td>
++ <td valign="baseline" class="right-column">
++ &nbsp;
++ <ul>
++ <li> <a href="http://www.python.org/cgi-bin/faqw.py" class="title"
++ >FAQ (online wizard)</a>
++ <br>(maybe more recent)
++ </ul>
++ </td>
++ </tr>
+ </tbody>
+ </table>
+ <p>
diff --git a/debian/patches/ensurepip-disabled.diff b/debian/patches/ensurepip-disabled.diff
new file mode 100644
index 0000000..e6ba0e4
--- /dev/null
+++ b/debian/patches/ensurepip-disabled.diff
@@ -0,0 +1,87 @@
+# DP: Disable ensurepip for the system installation, only enable it for virtual environments.
+
+Index: b/Lib/ensurepip/__init__.py
+===================================================================
+--- a/Lib/ensurepip/__init__.py
++++ b/Lib/ensurepip/__init__.py
+@@ -8,6 +8,34 @@ import tempfile
+
+ __all__ = ["version", "bootstrap"]
+
++def _ensurepip_is_disabled_in_debian_for_system():
++ # Detect if ensurepip is being executed inside of a python-virtualenv
++ # environment and return early if so.
++ if hasattr(sys, 'real_prefix'):
++ return
++
++ # Detect if ensurepip is being executed inside of a stdlib venv
++ # environment and return early if so.
++ if sys.prefix != getattr(sys, "base_prefix", sys.prefix):
++ return
++
++ # If we've gotten here, then we are running inside of the system Python
++ # and we don't want to use ensurepip to install into the system Python
++ # so instead we'll redirect the user to using dpkg and apt-get.
++ print('''\
++ensurepip is disabled in Debian/Ubuntu for the system python.
++
++Python modules for the system python are usually handled by dpkg and apt-get.
++
++ apt-get install python-<module name>
++
++Install the python-pip package to use pip itself. Using pip together
++with the system python might have unexpected results for any system installed
++module, so use it on your own risk, or make sure to only use it in virtual
++environments.
++''')
++ sys.exit(1)
++
+
+ # pip currently requires ssl support, so we try to provide a nicer
+ # error message when that is missing (http://bugs.python.org/issue19744)
+@@ -69,6 +97,11 @@ def bootstrap(*, root=None, upgrade=Fals
+
+ Note that calling this function will alter both sys.path and os.environ.
+ """
++
++ # Ensure that we are only running this inside of a virtual environment
++ # of some kind.
++ _ensurepip_is_disabled_in_debian_for_system()
++
+ if altinstall and default_pip:
+ raise ValueError("Cannot use altinstall and default_pip together")
+
+Index: b/Lib/venv/__init__.py
+===================================================================
+--- a/Lib/venv/__init__.py
++++ b/Lib/venv/__init__.py
+@@ -261,7 +261,28 @@ class EnvBuilder:
+ # intended for the global Python environment
+ cmd = [context.env_exe, '-Im', 'ensurepip', '--upgrade',
+ '--default-pip']
+- subprocess.check_output(cmd, stderr=subprocess.STDOUT)
++ # Debian 2015-09-18 barry@debian.org: <python>-venv is a separate
++ # binary package which might not be installed. In that case, the
++ # following command will produce an unhelpful error. Let's make it
++ # more user friendly.
++ try:
++ subprocess.check_output(
++ cmd, stderr=subprocess.STDOUT,
++ universal_newlines=True)
++ except subprocess.CalledProcessError:
++ print("""\
++The virtual environment was not created successfully because ensurepip is not
++available. On Debian/Ubuntu systems, you need to install the python3-venv
++package using the following command.
++
++ apt-get install python3-venv
++
++You may need to use sudo with that command. After installing the python3-venv
++package, recreate your virtual environment.
++
++Failing command: {}
++""".format(cmd))
++ sys.exit(1)
+
+ def setup_scripts(self, context):
+ """
diff --git a/debian/patches/ensurepip-wheels.diff b/debian/patches/ensurepip-wheels.diff
new file mode 100644
index 0000000..b60f956
--- /dev/null
+++ b/debian/patches/ensurepip-wheels.diff
@@ -0,0 +1,131 @@
+Index: b/Lib/ensurepip/__init__.py
+===================================================================
+--- a/Lib/ensurepip/__init__.py
++++ b/Lib/ensurepip/__init__.py
+@@ -1,3 +1,4 @@
++import glob
+ import os
+ import os.path
+ import pkgutil
+@@ -8,13 +9,9 @@ import tempfile
+ __all__ = ["version", "bootstrap"]
+
+
+-_SETUPTOOLS_VERSION = "28.8.0"
+-
+-_PIP_VERSION = "9.0.1"
+-
+ # pip currently requires ssl support, so we try to provide a nicer
+ # error message when that is missing (http://bugs.python.org/issue19744)
+-_MISSING_SSL_MESSAGE = ("pip {} requires SSL/TLS".format(_PIP_VERSION))
++_MISSING_SSL_MESSAGE = ("pip requires SSL/TLS")
+ try:
+ import ssl
+ except ImportError:
+@@ -26,8 +23,9 @@ else:
+ pass
+
+ _PROJECTS = [
+- ("setuptools", _SETUPTOOLS_VERSION),
+- ("pip", _PIP_VERSION),
++ "setuptools",
++ "pip",
++ "pkg_resources",
+ ]
+
+
+@@ -45,7 +43,10 @@ def version():
+ """
+ Returns a string specifying the bundled version of pip.
+ """
+- return _PIP_VERSION
++ wheel_names = glob.glob('/usr/share/python-wheels/pip-*.whl')
++ assert len(wheel_names) == 1, wheel_names
++ return os.path.basename(wheel_names[0]).split('-')[1]
++
+
+ def _disable_pip_configuration_settings():
+ # We deliberately ignore all pip environment variables
+@@ -87,20 +88,44 @@ def bootstrap(*, root=None, upgrade=Fals
+ # omit pip and easy_install
+ os.environ["ENSUREPIP_OPTIONS"] = "install"
+
++ # Debian: The bundled wheels are useless to us because we must use ones
++ # crafted from source code in the archive. As we build the virtual
++ # environment, copy the wheels from the system location into the virtual
++ # environment, and place those wheels on sys.path.
++ def copy_wheels(wheels, destdir, paths):
++ for project in wheels:
++ wheel_names = glob.glob(
++ '/usr/share/python-wheels/{}-*.whl'.format(project))
++ if len(wheel_names) == 0:
++ raise RuntimeError('missing dependency wheel %s' % project)
++ assert len(wheel_names) == 1, wheel_names
++ wheel_name = os.path.basename(wheel_names[0])
++ path = os.path.join('/usr/share/python-wheels', wheel_name)
++ with open(path, 'rb') as fp:
++ whl = fp.read()
++ dest = os.path.join(destdir, wheel_name)
++ with open(dest, 'wb') as fp:
++ fp.write(whl)
++ paths.append(dest)
++
+ with tempfile.TemporaryDirectory() as tmpdir:
++ # This directory is a "well known directory" which Debian has patched
++ # pip to look in when attempting to locate wheels to use to satisfy
++ # the dependencies that pip normally bundles but Debian has debundled.
++ # This is critically important and if this directory changes then both
++ # python-pip and python-virtualenv needs updated to match.
++ venv_wheel_dir = os.path.join(sys.prefix, 'share', 'python-wheels')
++ os.makedirs(venv_wheel_dir, exist_ok=True)
++ dependencies = [
++ os.path.basename(whl).split('-')[0]
++ for whl in glob.glob('/usr/share/python-wheels/*.whl')
++ ]
++ copy_wheels(dependencies, venv_wheel_dir, sys.path)
++
+ # Put our bundled wheels into a temporary directory and construct the
+ # additional paths that need added to sys.path
+ additional_paths = []
+- for project, version in _PROJECTS:
+- wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version)
+- whl = pkgutil.get_data(
+- "ensurepip",
+- "_bundled/{}".format(wheel_name),
+- )
+- with open(os.path.join(tmpdir, wheel_name), "wb") as fp:
+- fp.write(whl)
+-
+- additional_paths.append(os.path.join(tmpdir, wheel_name))
++ copy_wheels(_PROJECTS, tmpdir, additional_paths)
+
+ # Construct the arguments to be passed to the pip command
+ args = ["install", "--no-index", "--find-links", tmpdir]
+@@ -113,7 +138,7 @@ def bootstrap(*, root=None, upgrade=Fals
+ if verbosity:
+ args += ["-" + "v" * verbosity]
+
+- _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
++ _run_pip(args + _PROJECTS, additional_paths)
+
+ def _uninstall_helper(*, verbosity=0):
+ """Helper to support a clean default uninstall process on Windows
+@@ -127,7 +152,8 @@ def _uninstall_helper(*, verbosity=0):
+ return
+
+ # If the pip version doesn't match the bundled one, leave it alone
+- if pip.__version__ != _PIP_VERSION:
++ # Disabled for Debian, always using the version from the python3-pip package.
++ if False and pip.__version__ != _PIP_VERSION:
+ msg = ("ensurepip will only uninstall a matching version "
+ "({!r} installed, {!r} bundled)")
+ print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr)
+@@ -141,7 +167,7 @@ def _uninstall_helper(*, verbosity=0):
+ if verbosity:
+ args += ["-" + "v" * verbosity]
+
+- _run_pip(args + [p[0] for p in reversed(_PROJECTS)])
++ _run_pip(args + reversed(_PROJECTS))
+
+
+ def _main(argv=None):
diff --git a/debian/patches/ext-no-libpython-link.diff b/debian/patches/ext-no-libpython-link.diff
new file mode 100644
index 0000000..627d9d1
--- /dev/null
+++ b/debian/patches/ext-no-libpython-link.diff
@@ -0,0 +1,24 @@
+# DP: Don't link extensions with the shared libpython library.
+
+Index: b/Lib/distutils/command/build_ext.py
+===================================================================
+--- a/Lib/distutils/command/build_ext.py
++++ b/Lib/distutils/command/build_ext.py
+@@ -230,7 +230,7 @@ class build_ext(Command):
+ # For building extensions with a shared Python library,
+ # Python's library directory must be appended to library_dirs
+ # See Issues: #1600860, #4366
+- if (sysconfig.get_config_var('Py_ENABLE_SHARED')):
++ if False and (sysconfig.get_config_var('Py_ENABLE_SHARED')):
+ if not sysconfig.python_build:
+ # building third party extensions
+ self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
+@@ -746,7 +746,7 @@ class build_ext(Command):
+ return ext.libraries
+ else:
+ from distutils import sysconfig
+- if sysconfig.get_config_var('Py_ENABLE_SHARED'):
++ if False and sysconfig.get_config_var('Py_ENABLE_SHARED'):
+ pythonlib = 'python{}.{}{}'.format(
+ sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff,
+ sysconfig.get_config_var('ABIFLAGS'))
diff --git a/debian/patches/gdbm-import.diff b/debian/patches/gdbm-import.diff
new file mode 100644
index 0000000..2be2934
--- /dev/null
+++ b/debian/patches/gdbm-import.diff
@@ -0,0 +1,12 @@
+# DP: suggest installation of python3-gdbm package on failing _gdbm import
+
+--- a/Lib/dbm/gnu.py
++++ b/Lib/dbm/gnu.py
+@@ -1,3 +1,6 @@
+ """Provide the _gdbm module as a dbm submodule."""
+
+-from _gdbm import *
++try:
++ from _gdbm import *
++except ImportError as msg:
++ raise ImportError(str(msg) + ', please install the python3-gdbm package')
diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff
new file mode 100644
index 0000000..e4892ca
--- /dev/null
+++ b/debian/patches/git-updates.diff
@@ -0,0 +1,4 @@
+# DP: updates from the 3.5 branch (until 2017-xx-yy, ).
+
+# git diff 51ba5b7d0c194b0c2b1e5d647e70e3538b8dde3e ee9de30aa0dbcfd848e4200944674a084d963588 | filterdiff -x ?/.hgignore -x ?/.hgeol -x ?/.hgtags -x ?/.hgtouch -x ?/.gitignore -x ?/.gitattributes -x '?/.github/*' -x '?/.git*' -x ?/.codecov.yml -x ?/.travis.yml -x ?/configure --remove-timestamps
+
diff --git a/debian/patches/hurd-disable-nonworking-constants.diff b/debian/patches/hurd-disable-nonworking-constants.diff
new file mode 100644
index 0000000..d205bb8
--- /dev/null
+++ b/debian/patches/hurd-disable-nonworking-constants.diff
@@ -0,0 +1,38 @@
+# DP: Comment out constant exposed on the API which are not implemented on
+# DP: GNU/Hurd. They would not work at runtime anyway.
+
+Index: b/Modules/socketmodule.c
+===================================================================
+--- a/Modules/socketmodule.c
++++ b/Modules/socketmodule.c
+@@ -6485,9 +6485,11 @@ PyInit__socket(void)
+ #ifdef SO_OOBINLINE
+ PyModule_AddIntMacro(m, SO_OOBINLINE);
+ #endif
++#ifndef __GNU__
+ #ifdef SO_REUSEPORT
+ PyModule_AddIntMacro(m, SO_REUSEPORT);
+ #endif
++#endif
+ #ifdef SO_SNDBUF
+ PyModule_AddIntMacro(m, SO_SNDBUF);
+ #endif
+Index: b/Modules/posixmodule.c
+===================================================================
+--- a/Modules/posixmodule.c
++++ b/Modules/posixmodule.c
+@@ -12559,12 +12559,14 @@ all_ins(PyObject *m)
+ #ifdef O_LARGEFILE
+ if (PyModule_AddIntMacro(m, O_LARGEFILE)) return -1;
+ #endif
++#ifndef __GNU__
+ #ifdef O_SHLOCK
+ if (PyModule_AddIntMacro(m, O_SHLOCK)) return -1;
+ #endif
+ #ifdef O_EXLOCK
+ if (PyModule_AddIntMacro(m, O_EXLOCK)) return -1;
+ #endif
++#endif
+ #ifdef O_EXEC
+ if (PyModule_AddIntMacro(m, O_EXEC)) return -1;
+ #endif
diff --git a/debian/patches/issue21264.diff b/debian/patches/issue21264.diff
new file mode 100644
index 0000000..6c6287b
--- /dev/null
+++ b/debian/patches/issue21264.diff
@@ -0,0 +1,31 @@
+# DP: Fix issue #21264, test_compileall test failures in the installed location
+
+Index: b/Lib/test/test_compileall.py
+===================================================================
+--- a/Lib/test/test_compileall.py
++++ b/Lib/test/test_compileall.py
+@@ -249,20 +249,20 @@
+ os.utime(pycpath, (time.time()-60,)*2)
+ mtime = os.stat(pycpath).st_mtime
+ # Without force, no recompilation
+- self.assertRunOK(PYTHONPATH=self.directory)
++ self.assertRunOK(self.directory)
+ mtime2 = os.stat(pycpath).st_mtime
+ self.assertEqual(mtime, mtime2)
+ # Now force it.
+- self.assertRunOK('-f', PYTHONPATH=self.directory)
++ self.assertRunOK('-f', self.directory)
+ mtime2 = os.stat(pycpath).st_mtime
+ self.assertNotEqual(mtime, mtime2)
+
+ def test_no_args_respects_quiet_flag(self):
+ self._skip_if_sys_path_not_writable()
+ script_helper.make_script(self.directory, 'baz', '')
+- noisy = self.assertRunOK(PYTHONPATH=self.directory)
++ noisy = self.assertRunOK(self.directory)
+ self.assertIn(b'Listing ', noisy)
+- quiet = self.assertRunOK('-q', PYTHONPATH=self.directory)
++ quiet = self.assertRunOK('-q', self.directory)
+ self.assertNotIn(b'Listing ', quiet)
+
+ # Ensure that the default behavior of compileall's CLI is to create
diff --git a/debian/patches/langpack-gettext.diff b/debian/patches/langpack-gettext.diff
new file mode 100644
index 0000000..56deb77
--- /dev/null
+++ b/debian/patches/langpack-gettext.diff
@@ -0,0 +1,36 @@
+# DP: Description: support alternative gettext tree in
+# DP: /usr/share/locale-langpack; if a file is present in both trees,
+# DP: prefer the newer one
+# DP: Upstream status: Ubuntu-Specific
+
+Index: b/Lib/gettext.py
+===================================================================
+--- a/Lib/gettext.py
++++ b/Lib/gettext.py
+@@ -491,11 +491,26 @@ def find(domain, localedir=None, languag
+ if lang == 'C':
+ break
+ mofile = os.path.join(localedir, lang, 'LC_MESSAGES', '%s.mo' % domain)
++ mofile_lp = os.path.join("/usr/share/locale-langpack", lang,
++ 'LC_MESSAGES', '%s.mo' % domain)
++
++ # first look into the standard locale dir, then into the
++ # langpack locale dir
++
++ # standard mo file
+ if os.path.exists(mofile):
+ if all:
+ result.append(mofile)
+ else:
+ return mofile
++
++ # langpack mofile -> use it
++ if os.path.exists(mofile_lp):
++ if all:
++ result.append(mofile_lp)
++ else:
++ return mofile_lp
++
+ return result
+
+
diff --git a/debian/patches/lib-argparse.diff b/debian/patches/lib-argparse.diff
new file mode 100644
index 0000000..c9d604a
--- /dev/null
+++ b/debian/patches/lib-argparse.diff
@@ -0,0 +1,22 @@
+# DP: argparse.py: Make the gettext import conditional
+
+--- a/Lib/argparse.py
++++ b/Lib/argparse.py
+@@ -90,7 +90,16 @@
+ import sys as _sys
+ import textwrap as _textwrap
+
+-from gettext import gettext as _, ngettext
++try:
++ from gettext import gettext as _, ngettext
++except ImportError:
++ def _(message):
++ return message
++ def ngettext(singular,plural,n):
++ if n == 1:
++ return singular
++ else:
++ return plural
+
+
+ SUPPRESS = '==SUPPRESS=='
diff --git a/debian/patches/lib2to3-no-pgen-caching.diff b/debian/patches/lib2to3-no-pgen-caching.diff
new file mode 100644
index 0000000..e04685a
--- /dev/null
+++ b/debian/patches/lib2to3-no-pgen-caching.diff
@@ -0,0 +1,76 @@
+Index: b/Lib/lib2to3/tests/test_parser.py
+===================================================================
+--- a/Lib/lib2to3/tests/test_parser.py
++++ b/Lib/lib2to3/tests/test_parser.py
+@@ -36,71 +36,6 @@
+ self.assertEqual(t.children[1].children[0].type, syms.print_stmt)
+
+
+-class TestPgen2Caching(support.TestCase):
+- def test_load_grammar_from_txt_file(self):
+- pgen2_driver.load_grammar(support.grammar_path, save=False, force=True)
+-
+- def test_load_grammar_from_pickle(self):
+- # Make a copy of the grammar file in a temp directory we are
+- # guaranteed to be able to write to.
+- tmpdir = tempfile.mkdtemp()
+- try:
+- grammar_copy = os.path.join(
+- tmpdir, os.path.basename(support.grammar_path))
+- shutil.copy(support.grammar_path, grammar_copy)
+- pickle_name = pgen2_driver._generate_pickle_name(grammar_copy)
+-
+- pgen2_driver.load_grammar(grammar_copy, save=True, force=True)
+- self.assertTrue(os.path.exists(pickle_name))
+-
+- os.unlink(grammar_copy) # Only the pickle remains...
+- pgen2_driver.load_grammar(grammar_copy, save=False, force=False)
+- finally:
+- shutil.rmtree(tmpdir)
+-
+- @unittest.skipIf(sys.executable is None, 'sys.executable required')
+- def test_load_grammar_from_subprocess(self):
+- tmpdir = tempfile.mkdtemp()
+- tmpsubdir = os.path.join(tmpdir, 'subdir')
+- try:
+- os.mkdir(tmpsubdir)
+- grammar_base = os.path.basename(support.grammar_path)
+- grammar_copy = os.path.join(tmpdir, grammar_base)
+- grammar_sub_copy = os.path.join(tmpsubdir, grammar_base)
+- shutil.copy(support.grammar_path, grammar_copy)
+- shutil.copy(support.grammar_path, grammar_sub_copy)
+- pickle_name = pgen2_driver._generate_pickle_name(grammar_copy)
+- pickle_sub_name = pgen2_driver._generate_pickle_name(
+- grammar_sub_copy)
+- self.assertNotEqual(pickle_name, pickle_sub_name)
+-
+- # Generate a pickle file from this process.
+- pgen2_driver.load_grammar(grammar_copy, save=True, force=True)
+- self.assertTrue(os.path.exists(pickle_name))
+-
+- # Generate a new pickle file in a subprocess with a most likely
+- # different hash randomization seed.
+- sub_env = dict(os.environ)
+- sub_env['PYTHONHASHSEED'] = 'random'
+- subprocess.check_call(
+- [sys.executable, '-c', """
+-from lib2to3.pgen2 import driver as pgen2_driver
+-pgen2_driver.load_grammar(%r, save=True, force=True)
+- """ % (grammar_sub_copy,)],
+- env=sub_env)
+- self.assertTrue(os.path.exists(pickle_sub_name))
+-
+- with open(pickle_name, 'rb') as pickle_f_1, \
+- open(pickle_sub_name, 'rb') as pickle_f_2:
+- self.assertEqual(
+- pickle_f_1.read(), pickle_f_2.read(),
+- msg='Grammar caches generated using different hash seeds'
+- ' were not identical.')
+- finally:
+- shutil.rmtree(tmpdir)
+-
+-
+-
+ class GrammarTest(support.TestCase):
+ def validate(self, code):
+ support.parse_string(code)
diff --git a/debian/patches/lib2to3-no-pickled-grammar.diff b/debian/patches/lib2to3-no-pickled-grammar.diff
new file mode 100644
index 0000000..cc83155
--- /dev/null
+++ b/debian/patches/lib2to3-no-pickled-grammar.diff
@@ -0,0 +1,16 @@
+Index: b/Lib/lib2to3/pgen2/driver.py
+===================================================================
+--- a/Lib/lib2to3/pgen2/driver.py
++++ b/Lib/lib2to3/pgen2/driver.py
+@@ -122,7 +122,10 @@ def load_grammar(gt="Grammar.txt", gp=No
+ if force or not _newer(gp, gt):
+ logger.info("Generating grammar tables from %s", gt)
+ g = pgen.generate_grammar(gt)
+- if save:
++ # the pickle files mismatch, when built on different architectures.
++ # don't save these for now. An alternative solution might be to
++ # include the multiarch triplet into the file name
++ if False:
+ logger.info("Writing grammar tables to %s", gp)
+ try:
+ g.dump(gp)
diff --git a/debian/patches/link-opt.diff b/debian/patches/link-opt.diff
new file mode 100644
index 0000000..c61ae2e
--- /dev/null
+++ b/debian/patches/link-opt.diff
@@ -0,0 +1,26 @@
+# DP: Call the linker with -O1 -Bsymbolic-functions
+
+Index: b/configure.ac
+===================================================================
+--- a/configure.ac
++++ b/configure.ac
+@@ -2449,8 +2449,8 @@ then
+ fi
+ ;;
+ Linux*|GNU*|QNX*)
+- LDSHARED='$(CC) -shared'
+- LDCXXSHARED='$(CXX) -shared';;
++ LDSHARED='$(CC) -shared -Wl,-O1 -Wl,-Bsymbolic-functions'
++ LDCXXSHARED='$(CXX) -shared -Wl,-O1 -Wl,-Bsymbolic-functions';;
+ BSD/OS*/4*)
+ LDSHARED="gcc -shared"
+ LDCXXSHARED="g++ -shared";;
+@@ -2548,7 +2548,7 @@ then
+ LINKFORSHARED="-Wl,-E -Wl,+s";;
+ # LINKFORSHARED="-Wl,-E -Wl,+s -Wl,+b\$(BINLIBDEST)/lib-dynload";;
+ BSD/OS/4*) LINKFORSHARED="-Xlinker -export-dynamic";;
+- Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";;
++ Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions";;
+ # -u libsys_s pulls in all symbols in libsys
+ Darwin/*)
+ LINKFORSHARED="$extra_undefs -framework CoreFoundation"
diff --git a/debian/patches/link-timemodule.diff b/debian/patches/link-timemodule.diff
new file mode 100644
index 0000000..45e4153
--- /dev/null
+++ b/debian/patches/link-timemodule.diff
@@ -0,0 +1,13 @@
+Index: b/Modules/Setup.dist
+===================================================================
+--- a/Modules/Setup.dist
++++ b/Modules/Setup.dist
+@@ -118,7 +118,7 @@ _collections _collectionsmodule.c # Cont
+ itertools itertoolsmodule.c # Functions creating iterators for efficient looping
+ atexit atexitmodule.c # Register functions to be run at interpreter-shutdown
+ _stat _stat.c # stat.h interface
+-time timemodule.c # -lm # time operations and variables
++time timemodule.c -lrt # -lm # time operations and variables
+
+ # access to ISO C locale support
+ _locale _localemodule.c # -lintl
diff --git a/debian/patches/local-blurb.diff b/debian/patches/local-blurb.diff
new file mode 100644
index 0000000..a2e812c
--- /dev/null
+++ b/debian/patches/local-blurb.diff
@@ -0,0 +1,13 @@
+Index: b/Doc/Makefile
+===================================================================
+--- a/Doc/Makefile
++++ b/Doc/Makefile
+@@ -6,7 +6,7 @@
+ # You can set these variables from the command line.
+ PYTHON = python3
+ SPHINXBUILD = sphinx-build
+-BLURB = $(PYTHON) -m blurb
++BLURB = $(BLURB_ENV) $(PYTHON) -m blurb
+ PAPER =
+ SOURCES =
+ DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py)
diff --git a/debian/patches/locale-module.diff b/debian/patches/locale-module.diff
new file mode 100644
index 0000000..1245cc4
--- /dev/null
+++ b/debian/patches/locale-module.diff
@@ -0,0 +1,19 @@
+# DP: * Lib/locale.py:
+# DP: - Don't map 'utf8', 'utf-8' to 'utf', which is not a known encoding
+# DP: for glibc.
+
+Index: b/Lib/locale.py
+===================================================================
+--- a/Lib/locale.py
++++ b/Lib/locale.py
+@@ -1335,8 +1335,8 @@ locale_alias = {
+ 'ug_cn': 'ug_CN.UTF-8',
+ 'uk': 'uk_UA.KOI8-U',
+ 'uk_ua': 'uk_UA.KOI8-U',
+- 'univ': 'en_US.utf',
+- 'universal': 'en_US.utf',
++ 'univ': 'en_US.UTF-8',
++ 'universal': 'en_US.UTF-8',
+ 'universal.utf8@ucs4': 'en_US.UTF-8',
+ 'unm_us': 'unm_US.UTF-8',
+ 'ur': 'ur_PK.CP1256',
diff --git a/debian/patches/lto-link-flags.diff b/debian/patches/lto-link-flags.diff
new file mode 100644
index 0000000..046e8d2
--- /dev/null
+++ b/debian/patches/lto-link-flags.diff
@@ -0,0 +1,22 @@
+Index: b/Makefile.pre.in
+===================================================================
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -141,7 +141,7 @@ CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$
+ SHLIB_SUFFIX= @SHLIB_SUFFIX@
+ EXT_SUFFIX= @EXT_SUFFIX@
+ LDSHARED= @LDSHARED@ $(PY_LDFLAGS)
+-BLDSHARED= @BLDSHARED@ $(PY_LDFLAGS)
++BLDSHARED= @BLDSHARED@ $(PY_LDFLAGS) $(PY_CFLAGS)
+ LDCXXSHARED= @LDCXXSHARED@
+ DESTSHARED= $(BINLIBDEST)/lib-dynload
+
+@@ -548,7 +548,7 @@ clinic: $(BUILDPYTHON)
+
+ # Build the interpreter
+ $(BUILDPYTHON): Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
+- $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
++ $(LINKCC) $(PY_LDFLAGS) $(PY_CFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+
+ platform: $(BUILDPYTHON) pybuilddir.txt
+ $(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print(get_platform()+"-"+sys.version[0:3])' >platform
diff --git a/debian/patches/makesetup-bashism.diff b/debian/patches/makesetup-bashism.diff
new file mode 100644
index 0000000..96fd289
--- /dev/null
+++ b/debian/patches/makesetup-bashism.diff
@@ -0,0 +1,15 @@
+# DP: Fix bashism in makesetup shell script
+
+Index: b/Modules/makesetup
+===================================================================
+--- a/Modules/makesetup
++++ b/Modules/makesetup
+@@ -279,7 +279,7 @@ sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' |
+ -) ;;
+ *) sedf="@sed.in.$$"
+ trap 'rm -f $sedf' 0 1 2 3
+- echo "1i\\" >$sedf
++ printf "1i\\" >$sedf
+ str="# Generated automatically from $makepre by makesetup."
+ echo "$str" >>$sedf
+ echo "s%_MODNAMES_%$NAMES%" >>$sedf
diff --git a/debian/patches/mangle-fstack-protector.diff b/debian/patches/mangle-fstack-protector.diff
new file mode 100644
index 0000000..19b27f7
--- /dev/null
+++ b/debian/patches/mangle-fstack-protector.diff
@@ -0,0 +1,26 @@
+# DP: When using GCC versions older than 4.9, automagically mangle
+# DP: -fstack-protector-strong to -fstack-protector
+
+Index: b/Lib/distutils/sysconfig.py
+===================================================================
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -13,6 +13,7 @@ import _imp
+ import os
+ import re
+ import sys
++import fnmatch
+
+ from .errors import DistutilsPlatformError
+
+@@ -197,6 +198,10 @@ def customize_compiler(compiler):
+ cc = newcc
+ if 'CXX' in os.environ:
+ cxx = os.environ['CXX']
++ if fnmatch.filter([cc, cxx], '*-4.[0-8]'):
++ configure_cflags = configure_cflags.replace('-fstack-protector-strong', '-fstack-protector')
++ ldshared = ldshared.replace('-fstack-protector-strong', '-fstack-protector')
++ cflags = cflags.replace('-fstack-protector-strong', '-fstack-protector')
+ if 'LDSHARED' in os.environ:
+ ldshared = os.environ['LDSHARED']
+ if 'CPP' in os.environ:
diff --git a/debian/patches/mpdecimal-version.diff b/debian/patches/mpdecimal-version.diff
new file mode 100644
index 0000000..e31c90b
--- /dev/null
+++ b/debian/patches/mpdecimal-version.diff
@@ -0,0 +1,17 @@
+# DP: Relax the mpdecimal version check
+
+Index: b/Modules/_decimal/_decimal.c
+===================================================================
+--- a/Modules/_decimal/_decimal.c
++++ b/Modules/_decimal/_decimal.c
+@@ -39,10 +39,6 @@
+ #include "memory.h"
+
+
+-#if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02040100
+- #error "libmpdec version >= 2.4.1 required"
+-#endif
+-
+
+ /*
+ * Type sizes with assertions in mpdecimal.h and pyport.h:
diff --git a/debian/patches/multiarch-extname.diff b/debian/patches/multiarch-extname.diff
new file mode 100644
index 0000000..61d1384
--- /dev/null
+++ b/debian/patches/multiarch-extname.diff
@@ -0,0 +1,92 @@
+# DP: Make sure to rename extensions to a tag including the MULTIARCH name
+
+this patch can be dropped for python3.5 final, if the upstream chage is kept.
+
+Index: b/Lib/distutils/dir_util.py
+===================================================================
+--- a/Lib/distutils/dir_util.py
++++ b/Lib/distutils/dir_util.py
+@@ -96,6 +96,9 @@ def create_tree(base_dir, files, mode=0o
+ for dir in sorted(need_dir):
+ mkpath(dir, mode, verbose=verbose, dry_run=dry_run)
+
++import sysconfig
++_multiarch = None
++
+ def copy_tree(src, dst, preserve_mode=1, preserve_times=1,
+ preserve_symlinks=0, update=0, verbose=1, dry_run=0):
+ """Copy an entire directory tree 'src' to a new location 'dst'.
+@@ -131,6 +134,13 @@ def copy_tree(src, dst, preserve_mode=1,
+ raise DistutilsFileError(
+ "error listing files in '%s': %s" % (src, e.strerror))
+
++ ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX')
++ _multiarch = sysconfig.get_config_var ('MULTIARCH')
++ if ext_suffix.endswith(_multiarch + ext_suffix[-3:]):
++ new_suffix = None
++ else:
++ new_suffix = "%s-%s%s" % (ext_suffix[:-3], _multiarch, ext_suffix[-3:])
++
+ if not dry_run:
+ mkpath(dst, verbose=verbose)
+
+@@ -139,6 +149,9 @@ def copy_tree(src, dst, preserve_mode=1,
+ for n in names:
+ src_name = os.path.join(src, n)
+ dst_name = os.path.join(dst, n)
++ if new_suffix and _multiarch and n.endswith(ext_suffix) and not n.endswith(new_suffix):
++ dst_name = os.path.join(dst, n.replace(ext_suffix, new_suffix))
++ log.info("renaming extension %s -> %s", n, n.replace(ext_suffix, new_suffix))
+
+ if n.startswith('.nfs'):
+ # skip NFS rename files
+Index: b/Lib/distutils/command/install_lib.py
+===================================================================
+--- a/Lib/distutils/command/install_lib.py
++++ b/Lib/distutils/command/install_lib.py
+@@ -56,6 +56,7 @@ class install_lib(Command):
+ self.compile = None
+ self.optimize = None
+ self.skip_build = None
++ self.multiarch = None # if we should rename the extensions
+
+ def finalize_options(self):
+ # Get all the information we need to install pure Python modules
+@@ -68,6 +69,7 @@ class install_lib(Command):
+ ('compile', 'compile'),
+ ('optimize', 'optimize'),
+ ('skip_build', 'skip_build'),
++ ('multiarch', 'multiarch'),
+ )
+
+ if self.compile is None:
+@@ -108,6 +110,8 @@ class install_lib(Command):
+
+ def install(self):
+ if os.path.isdir(self.build_dir):
++ import distutils.dir_util
++ distutils.dir_util._multiarch = self.multiarch
+ outfiles = self.copy_tree(self.build_dir, self.install_dir)
+ else:
+ self.warn("'%s' does not exist -- no Python modules to install" %
+Index: b/Lib/distutils/command/install.py
+===================================================================
+--- a/Lib/distutils/command/install.py
++++ b/Lib/distutils/command/install.py
+@@ -192,6 +192,7 @@ class install(Command):
+
+ # enable custom installation, known values: deb
+ self.install_layout = None
++ self.multiarch = None
+
+ self.compile = None
+ self.optimize = None
+@@ -449,6 +450,8 @@ class install(Command):
+ self.install_platbase = self.exec_prefix
+ if self.install_layout:
+ if self.install_layout.lower() in ['deb']:
++ import sysconfig
++ self.multiarch = sysconfig.get_config_var('MULTIARCH')
+ self.select_scheme("deb_system")
+ elif self.install_layout.lower() in ['unix']:
+ self.select_scheme("unix_prefix")
diff --git a/debian/patches/multiarch.diff b/debian/patches/multiarch.diff
new file mode 100644
index 0000000..d37f044
--- /dev/null
+++ b/debian/patches/multiarch.diff
@@ -0,0 +1,136 @@
+Index: b/Lib/sysconfig.py
+===================================================================
+--- a/Lib/sysconfig.py
++++ b/Lib/sysconfig.py
+@@ -337,6 +337,8 @@ def get_makefile_filename():
+ config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags)
+ else:
+ config_dir_name = 'config'
++ if hasattr(sys.implementation, '_multiarch'):
++ config_dir_name += '-%s' % sys.implementation._multiarch
+ return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
+
+ def _generate_posix_vars():
+@@ -543,6 +545,12 @@ def get_config_vars(*args):
+ # the init-function.
+ _CONFIG_VARS['userbase'] = _getuserbase()
+
++ multiarch = get_config_var('MULTIARCH')
++ if multiarch:
++ _CONFIG_VARS['multiarchsubdir'] = '/' + multiarch
++ else:
++ _CONFIG_VARS['multiarchsubdir'] = ''
++
+ # Always convert srcdir to an absolute path
+ srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
+ if os.name == 'posix':
+Index: b/Lib/distutils/sysconfig.py
+===================================================================
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -99,6 +99,9 @@ def get_python_inc(plat_specific=0, pref
+ incdir = os.path.join(get_config_var('srcdir'), 'Include')
+ return os.path.normpath(incdir)
+ python_dir = 'python' + get_python_version() + build_flags
++ if not python_build and plat_specific:
++ import sysconfig
++ return sysconfig.get_path('platinclude')
+ return os.path.join(prefix, "include", python_dir)
+ elif os.name == "nt":
+ return os.path.join(prefix, "include")
+@@ -257,6 +260,8 @@ def get_makefile_filename():
+ return os.path.join(_sys_home or project_base, "Makefile")
+ lib_dir = get_python_lib(plat_specific=0, standard_lib=1)
+ config_file = 'config-{}{}'.format(get_python_version(), build_flags)
++ if hasattr(sys.implementation, '_multiarch'):
++ config_file += '-%s' % sys.implementation._multiarch
+ return os.path.join(lib_dir, config_file, 'Makefile')
+
+
+Index: b/Makefile.pre.in
+===================================================================
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -759,6 +759,7 @@ Modules/signalmodule.o: $(srcdir)/Module
+
+ Python/dynload_shlib.o: $(srcdir)/Python/dynload_shlib.c Makefile
+ $(CC) -c $(PY_CORE_CFLAGS) \
++ $(if $(MULTIARCH),-DMULTIARCH='"$(MULTIARCH)"') \
+ -DSOABI='"$(SOABI)"' \
+ -o $@ $(srcdir)/Python/dynload_shlib.c
+
+@@ -770,6 +771,7 @@ Python/dynload_hpux.o: $(srcdir)/Python/
+ Python/sysmodule.o: $(srcdir)/Python/sysmodule.c Makefile
+ $(CC) -c $(PY_CORE_CFLAGS) \
+ -DABIFLAGS='"$(ABIFLAGS)"' \
++ -DMULTIARCH='"$(MULTIARCH)"' \
+ -o $@ $(srcdir)/Python/sysmodule.c
+
+ $(IO_OBJS): $(IO_H)
+@@ -1336,6 +1338,10 @@ libinstall: build_all $(srcdir)/Lib/$(PL
+ $(srcdir)/Lib/$(PLATDIR):
+ mkdir $(srcdir)/Lib/$(PLATDIR)
+ cp $(srcdir)/Lib/plat-generic/regen $(srcdir)/Lib/$(PLATDIR)/regen
++ if [ -n "$(MULTIARCH)" ]; then \
++ cp -p $(srcdir)/Lib/plat-linux/*.py $(srcdir)/Lib/$(PLATDIR)/.; \
++ rm -f $(srcdir)/Lib/$(PLATDIR)/IN.py; \
++ fi
+ export PATH; PATH="`pwd`:$$PATH"; \
+ export PYTHONPATH; PYTHONPATH="`pwd`/Lib"; \
+ export DYLD_FRAMEWORK_PATH; DYLD_FRAMEWORK_PATH="`pwd`"; \
+@@ -1386,7 +1392,7 @@ inclinstall:
+ LIBPL= @LIBPL@
+
+ # pkgconfig directory
+-LIBPC= $(LIBDIR)/pkgconfig
++LIBPC= $(LIBDIR)/$(MULTIARCH)/pkgconfig
+
+ libainstall: @DEF_MAKE_RULE@ python-config
+ @for i in $(LIBDIR) $(LIBPL) $(LIBPC); \
+Index: b/Python/sysmodule.c
+===================================================================
+--- a/Python/sysmodule.c
++++ b/Python/sysmodule.c
+@@ -1733,6 +1733,15 @@ make_impl_info(PyObject *version_info)
+ if (res < 0)
+ goto error;
+
++ /* For Debian multiarch support. */
++ value = PyUnicode_FromString(MULTIARCH);
++ if (value == NULL)
++ goto error;
++ res = PyDict_SetItemString(impl_info, "_multiarch", value);
++ Py_DECREF(value);
++ if (res < 0)
++ goto error;
++
+ /* dict ready */
+
+ ns = _PyNamespace_New(impl_info);
+Index: b/configure.ac
+===================================================================
+--- a/configure.ac
++++ b/configure.ac
+@@ -874,7 +874,12 @@ if test x$PLATFORM_TRIPLET != x && test
+ AC_MSG_ERROR([internal configure error for the platform triplet, please file a bug report])
+ fi
+ fi
+-PLATDIR=plat-$MACHDEP
++
++if test x$PLATFORM_TRIPLET = x; then
++ PLATDIR=plat-$MACHDEP
++else
++ PLATDIR=plat-$PLATFORM_TRIPLET
++fi
+ AC_SUBST(PLATDIR)
+ AC_SUBST(PLATFORM_TRIPLET)
+
+@@ -4550,7 +4555,7 @@ AC_MSG_RESULT($LDVERSION)
+
+ dnl define LIBPL after ABIFLAGS and LDVERSION is defined.
+ AC_SUBST(PY_ENABLE_SHARED)
+-LIBPL='$(prefix)'"/lib/python${VERSION}/config-${LDVERSION}"
++LIBPL='${prefix}'"/lib/python${VERSION}/config-${LDVERSION}-${MULTIARCH}"
+ AC_SUBST(LIBPL)
+
+ # Check whether right shifting a negative integer extends the sign bit
diff --git a/debian/patches/no-large-file-support.diff b/debian/patches/no-large-file-support.diff
new file mode 100644
index 0000000..78b9f12
--- /dev/null
+++ b/debian/patches/no-large-file-support.diff
@@ -0,0 +1,18 @@
+# DP: disable large file support for GNU/Hurd
+
+Index: b/configure.ac
+===================================================================
+--- a/configure.ac
++++ b/configure.ac
+@@ -2059,6 +2059,11 @@ if test "$sol_lfs_bug" = "yes"; then
+ use_lfs=no
+ fi
+
++# Don't use largefile support for GNU/Hurd
++case $ac_sys_system in GNU*)
++ use_lfs=no
++esac
++
+ if test "$use_lfs" = "yes"; then
+ # Two defines needed to enable largefile support on various platforms
+ # These may affect some typedefs
diff --git a/debian/patches/platform-lsbrelease.diff b/debian/patches/platform-lsbrelease.diff
new file mode 100644
index 0000000..3a3c2a4
--- /dev/null
+++ b/debian/patches/platform-lsbrelease.diff
@@ -0,0 +1,85 @@
+# DP: Use /etc/lsb-release to identify the platform.
+
+Index: b/Lib/platform.py
+===================================================================
+--- a/Lib/platform.py
++++ b/Lib/platform.py
+@@ -268,7 +268,7 @@ _release_version = re.compile(r'([^0-9]+
+ _supported_dists = (
+ 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
+ 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
+- 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
++ 'UnitedLinux', 'turbolinux', 'arch', 'mageia', 'Ubuntu')
+
+ def _parse_release_file(firstline):
+
+@@ -297,6 +297,10 @@ def _parse_release_file(firstline):
+ id = l[1]
+ return '', version, id
+
++_distributor_id_file_re = re.compile("(?:DISTRIB_ID\s*=)\s*(.*)", re.I)
++_release_file_re = re.compile("(?:DISTRIB_RELEASE\s*=)\s*(.*)", re.I)
++_codename_file_re = re.compile("(?:DISTRIB_CODENAME\s*=)\s*(.*)", re.I)
++
+ def linux_distribution(distname='', version='', id='',
+
+ supported_dists=_supported_dists,
+@@ -329,6 +333,25 @@ def _linux_distribution(distname, versio
+ args given as parameters.
+
+ """
++ # check for the Debian/Ubuntu /etc/lsb-release file first, needed so
++ # that the distribution doesn't get identified as Debian.
++ try:
++ with open("/etc/lsb-release", "r") as etclsbrel:
++ for line in etclsbrel:
++ m = _distributor_id_file_re.search(line)
++ if m:
++ _u_distname = m.group(1).strip()
++ m = _release_file_re.search(line)
++ if m:
++ _u_version = m.group(1).strip()
++ m = _codename_file_re.search(line)
++ if m:
++ _u_id = m.group(1).strip()
++ if _u_distname and _u_version:
++ return (_u_distname, _u_version, _u_id)
++ except (EnvironmentError, UnboundLocalError):
++ pass
++
+ try:
+ etc = os.listdir(_UNIXCONFDIR)
+ except OSError:
+Index: b/Lib/test/test_platform.py
+===================================================================
+--- a/Lib/test/test_platform.py
++++ b/Lib/test/test_platform.py
+@@ -327,28 +327,6 @@ class PlatformTest(unittest.TestCase):
+ returncode = ret >> 8
+ self.assertEqual(returncode, len(data))
+
+- def test_linux_distribution_encoding(self):
+- # Issue #17429
+- with tempfile.TemporaryDirectory() as tempdir:
+- filename = os.path.join(tempdir, 'fedora-release')
+- with open(filename, 'w', encoding='utf-8') as f:
+- f.write('Fedora release 19 (Schr\xf6dinger\u2019s Cat)\n')
+-
+- with mock.patch('platform._UNIXCONFDIR', tempdir):
+- with warnings.catch_warnings():
+- warnings.filterwarnings(
+- 'ignore',
+- 'dist\(\) and linux_distribution\(\) '
+- 'functions are deprecated .*',
+- PendingDeprecationWarning,
+- )
+- distname, version, distid = platform.linux_distribution()
+-
+- self.assertEqual(distname, 'Fedora')
+- self.assertEqual(version, '19')
+- self.assertEqual(distid, 'Schr\xf6dinger\u2019s Cat')
+-
+-
+ class DeprecationTest(unittest.TestCase):
+
+ def test_dist_deprecation(self):
diff --git a/debian/patches/profiled-build.diff b/debian/patches/profiled-build.diff
new file mode 100644
index 0000000..508b30a
--- /dev/null
+++ b/debian/patches/profiled-build.diff
@@ -0,0 +1,23 @@
+# DP: Ignore errors in the profile task.
+
+Index: b/Makefile.pre.in
+===================================================================
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -479,6 +479,16 @@ build_all_generate_profile:
+ run_profile_task:
+ : # FIXME: can't run for a cross build
+ $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $(PROFILE_TASK) || true
++ task="$(PROFILE_TASK)"; \
++ case "$$task" in \
++ *-s\ *) \
++ $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $$task; \
++ while [ -f $(srcdir)/build/pynexttest ]; do \
++ $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $$task; \
++ done;; \
++ *) \
++ $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $$task; \
++ esac
+
+ build_all_merge_profile:
+ $(LLVM_PROF_MERGER)
diff --git a/debian/patches/pydoc-use-pager.diff b/debian/patches/pydoc-use-pager.diff
new file mode 100644
index 0000000..1a4c2af
--- /dev/null
+++ b/debian/patches/pydoc-use-pager.diff
@@ -0,0 +1,15 @@
+# DP: pydoc: use the pager command if available.
+
+Index: b/Lib/pydoc.py
+===================================================================
+--- a/Lib/pydoc.py
++++ b/Lib/pydoc.py
+@@ -1439,6 +1439,8 @@ def getpager():
+ return plainpager
+ if sys.platform == 'win32':
+ return lambda text: tempfilepager(plain(text), 'more <')
++ if hasattr(os, 'system') and os.system('(pager) 2>/dev/null') == 0:
++ return lambda text: pipepager(text, 'pager')
+ if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
+ return lambda text: pipepager(text, 'less')
+
diff --git a/debian/patches/pyhash.diff b/debian/patches/pyhash.diff
new file mode 100644
index 0000000..b9eec8b
--- /dev/null
+++ b/debian/patches/pyhash.diff
@@ -0,0 +1,17 @@
+Index: b/Python/pyhash.c
+===================================================================
+--- a/Python/pyhash.c
++++ b/Python/pyhash.c
+@@ -384,7 +384,12 @@ siphash24(const void *src, Py_ssize_t sr
+ PY_UINT8_T *m;
+
+ while (src_sz >= 8) {
++#if defined(__ARM_EABI__) && defined(__ARMEL__)
++ PY_UINT64_T mi;
++ memcpy(&mi, in, sizeof(PY_UINT64_T));
++#else
+ PY_UINT64_T mi = _le64toh(*in);
++#endif
+ in += 1;
+ src_sz -= 8;
+ v3 ^= mi;
diff --git a/debian/patches/reproducible-buildinfo.diff b/debian/patches/reproducible-buildinfo.diff
new file mode 100644
index 0000000..a0b20f9
--- /dev/null
+++ b/debian/patches/reproducible-buildinfo.diff
@@ -0,0 +1,15 @@
+# DP: Build getbuildinfo.o with DATE/TIME values when defined
+
+Index: b/Makefile.pre.in
+===================================================================
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -731,6 +731,8 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \
+ -DGITVERSION="\"`LC_ALL=C $(GITVERSION)`\"" \
+ -DGITTAG="\"`LC_ALL=C $(GITTAG)`\"" \
+ -DGITBRANCH="\"`LC_ALL=C $(GITBRANCH)`\"" \
++ $(if $(BUILD_DATE),-DDATE='"$(BUILD_DATE)"') \
++ $(if $(BUILD_TIME),-DTIME='"$(BUILD_TIME)"') \
+ -o $@ $(srcdir)/Modules/getbuildinfo.c
+
+ Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..d9ee29d
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,42 @@
+# git-updates.diff
+deb-setup.diff
+deb-locations.diff
+distutils-install-layout.diff
+locale-module.diff
+distutils-link.diff
+distutils-sysconfig.diff
+tkinter-import.diff
+gdbm-import.diff
+link-opt.diff
+setup-modules.diff
+platform-lsbrelease.diff
+bdist-wininst-notfound.diff
+profiled-build.diff
+makesetup-bashism.diff
+hurd-disable-nonworking-constants.diff
+langpack-gettext.diff
+no-large-file-support.diff
+disable-sem-check.diff
+lib-argparse.diff
+ctypes-arm.diff
+# link-timemodule.diff
+lto-link-flags.diff
+multiarch.diff
+lib2to3-no-pickled-grammar.diff
+ext-no-libpython-link.diff
+test-no-random-order.diff
+multiarch-extname.diff
+distutils-init.diff
+tempfile-minimal.diff
+disable-some-tests.diff
+# issue21264.diff
+ensurepip-wheels.diff
+ensurepip-disabled.diff
+mpdecimal-version.diff
+mangle-fstack-protector.diff
+reproducible-buildinfo.diff
+pydoc-use-pager.diff
+#asyncio366.diff
+pyhash.diff
+lib2to3-no-pgen-caching.diff
+local-blurb.diff
diff --git a/debian/patches/setup-modules.diff b/debian/patches/setup-modules.diff
new file mode 100644
index 0000000..d3c5789
--- /dev/null
+++ b/debian/patches/setup-modules.diff
@@ -0,0 +1,52 @@
+# DP: Modules/Setup.dist: patches to build some extensions statically
+
+Index: b/Modules/Setup.dist
+===================================================================
+--- a/Modules/Setup.dist
++++ b/Modules/Setup.dist
+@@ -175,7 +175,7 @@ _symtable symtablemodule.c
+ #_weakref _weakref.c # basic weak reference support
+ #_testcapi _testcapimodule.c # Python C API test module
+ #_random _randommodule.c # Random number generator
+-#_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator
++#_elementtree _elementtree.c -lexpat # elementtree accelerator
+ #_pickle _pickle.c # pickle accelerator
+ #_datetime _datetimemodule.c # datetime accelerator
+ #_bisect _bisectmodule.c # Bisection algorithms
+@@ -204,10 +204,7 @@ _symtable symtablemodule.c
+
+ # Socket module helper for SSL support; you must comment out the other
+ # socket line above, and possibly edit the SSL variable:
+-#SSL=/usr/local/ssl
+-#_ssl _ssl.c \
+-# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
+-# -L$(SSL)/lib -lssl -lcrypto
++#_ssl _ssl.c -lssl -lcrypto
+
+ # The crypt module is now disabled by default because it breaks builds
+ # on many systems (where -lcrypt is needed), e.g. Linux (I believe).
+@@ -249,6 +246,7 @@ _symtable symtablemodule.c
+ #_sha256 sha256module.c
+ #_sha512 sha512module.c
+
++#_hashlib _hashopenssl.c -lssl -lcrypto
+
+ # The _tkinter module.
+ #
+@@ -337,6 +335,7 @@ _symtable symtablemodule.c
+ # Fred Drake's interface to the Python parser
+ #parser parsermodule.c
+
++#_ctypes _ctypes/_ctypes.c _ctypes/callbacks.c _ctypes/callproc.c _ctypes/stgdict.c _ctypes/cfield.c _ctypes/malloc_closure.c -lffi
+
+ # Lee Busby's SIGFPE modules.
+ # The library to link fpectl with is platform specific.
+@@ -371,7 +370,7 @@ _symtable symtablemodule.c
+ #
+ # More information on Expat can be found at www.libexpat.org.
+ #
+-#pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI
++#pyexpat pyexpat.c -lexpat
+
+ # Hye-Shik Chang's CJKCodecs
+
diff --git a/debian/patches/sysconfig-debian-schemes.diff b/debian/patches/sysconfig-debian-schemes.diff
new file mode 100644
index 0000000..d26ee20
--- /dev/null
+++ b/debian/patches/sysconfig-debian-schemes.diff
@@ -0,0 +1,67 @@
+# DP: Add schemes 'deb_system' and 'posix_local', make the latter the default
+
+--- a/Lib/sysconfig.py
++++ b/Lib/sysconfig.py
+@@ -32,6 +32,30 @@
+ 'scripts': '{base}/bin',
+ 'data': '{base}',
+ },
++ 'deb_system': {
++ 'stdlib': '{installed_base}/lib/python{py_version_short}',
++ 'platstdlib': '{platbase}/lib/python{py_version_short}',
++ 'purelib': '{base}/lib/python3/dist-packages',
++ 'platlib': '{platbase}/lib/python3/dist-packages',
++ 'include':
++ '{installed_base}/include/python{py_version_short}{abiflags}',
++ 'platinclude':
++ '{installed_platbase}/include/python{py_version_short}{abiflags}',
++ 'scripts': '{base}/bin',
++ 'data': '{base}',
++ },
++ 'posix_local': {
++ 'stdlib': '{installed_base}/lib/python{py_version_short}',
++ 'platstdlib': '{platbase}/lib/python{py_version_short}',
++ 'purelib': '{base}/local/lib/python{py_version_short}/dist-packages',
++ 'platlib': '{platbase}/local/lib/python{py_version_short}/dist-packages',
++ 'include':
++ '{installed_base}/local/include/python{py_version_short}{abiflags}',
++ 'platinclude':
++ '{installed_platbase}/local/include/python{py_version_short}{abiflags}',
++ 'scripts': '{base}/local/bin',
++ 'data': '{base}',
++ },
+ 'posix_home': {
+ 'stdlib': '{installed_base}/lib/python',
+ 'platstdlib': '{base}/lib/python',
+@@ -162,7 +186,7 @@
+ _PYTHON_BUILD = is_python_build(True)
+
+ if _PYTHON_BUILD:
+- for scheme in ('posix_prefix', 'posix_home'):
++ for scheme in ('posix_prefix', 'posix_home', 'posix_local', 'deb_system'):
+ _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'
+ _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.'
+
+@@ -200,7 +224,12 @@
+ def _get_default_scheme():
+ if os.name == 'posix':
+ # the default scheme for posix is posix_prefix
+- return 'posix_prefix'
++ if 'real_prefix' in sys.__dict__ or 'VIRTUAL_ENV' in os.environ:
++ # virtual environments
++ return 'posix_prefix'
++ else:
++ # Debian default
++ return 'posix_local'
+ return os.name
+
+
+@@ -485,7 +514,7 @@
+ else:
+ inc_dir = _sys_home or _PROJECT_BASE
+ else:
+- inc_dir = get_path('platinclude')
++ inc_dir = get_path('platinclude', 'posix_prefix')
+ return os.path.join(inc_dir, 'pyconfig.h')
+
+
diff --git a/debian/patches/sysconfigdata.diff b/debian/patches/sysconfigdata.diff
new file mode 100644
index 0000000..5387689
--- /dev/null
+++ b/debian/patches/sysconfigdata.diff
@@ -0,0 +1,76 @@
+# DP: Issue #15298: Generate _sysconfigdata.py in the build dir, not the source dir.
+
+diff -r 2ecdda96f970 Lib/sysconfig.py
+--- a/Lib/sysconfig.py Tue Jul 10 18:27:54 2012 +0200
++++ b/Lib/sysconfig.py Tue Jul 10 22:06:43 2012 +0200
+@@ -390,7 +390,7 @@
+ if _PYTHON_BUILD:
+ vars['LDSHARED'] = vars['BLDSHARED']
+
+- destfile = os.path.join(os.path.dirname(__file__), '_sysconfigdata.py')
++ destfile = '_sysconfigdata.py'
+ with open(destfile, 'w', encoding='utf8') as f:
+ f.write('# system configuration generated and used by'
+ ' the sysconfig module\n')
+diff -r 2ecdda96f970 Makefile.pre.in
+--- a/Makefile.pre.in Tue Jul 10 18:27:54 2012 +0200
++++ b/Makefile.pre.in Tue Jul 10 22:06:43 2012 +0200
+@@ -410,7 +410,7 @@
+ Objects/unicodectype.o \
+ Objects/weakrefobject.o
+
+-SYSCONFIGDATA=$(srcdir)/Lib/_sysconfigdata.py
++SYSCONFIGDATA=_sysconfigdata.py
+
+ ##########################################################################
+ # objects that get linked into the Python library
+@@ -472,6 +472,9 @@
+ # Generate the sysconfig build-time data
+ $(SYSCONFIGDATA): $(BUILDPYTHON)
+ $(RUNSHARED) $(PYTHON_FOR_BUILD) -S -m sysconfig --generate-posix-vars
++ $(RUNSHARED) $(PYTHON_FOR_BUILD) -S -c 'import os,sys ; from distutils.util import get_platform ; d=os.path.join("build", "lib."+get_platform()+"-"+sys.version[0:3]+("-pydebug" if hasattr(sys, "gettotalrefcount") else "")); print(d, end="")' > pybuilddir.txt
++ mkdir -p `cat pybuilddir.txt`
++ cp $(SYSCONFIGDATA) `cat pybuilddir.txt`/.
+
+ # Build the shared modules
+ sharedmods: $(BUILDPYTHON) $(SYSCONFIGDATA)
+@@ -1036,7 +1039,7 @@
+ else true; \
+ fi; \
+ done
+- @for i in $(srcdir)/Lib/*.py ; \
++ @for i in $(srcdir)/Lib/*.py $(SYSCONFIGDATA); \
+ do \
+ if test -x $$i; then \
+ $(INSTALL_SCRIPT) $$i $(DESTDIR)$(LIBDEST); \
+diff -r 2ecdda96f970 setup.py
+--- a/setup.py Tue Jul 10 18:27:54 2012 +0200
++++ b/setup.py Tue Jul 10 22:06:43 2012 +0200
+@@ -33,10 +33,6 @@
+ # This global variable is used to hold the list of modules to be disabled.
+ disabled_module_list = []
+
+-# File which contains the directory for shared mods (for sys.path fixup
+-# when running from the build dir, see Modules/getpath.c)
+-_BUILDDIR_COOKIE = "pybuilddir.txt"
+-
+ def add_dir_to_list(dirlist, dir):
+ """Add the directory 'dir' to the list 'dirlist' (after any relative
+ directories) if:
+@@ -250,12 +246,9 @@
+ args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags
+ self.compiler.set_executables(**args)
+
+- # Not only do we write the builddir cookie, but we manually install
+- # the shared modules directory if it isn't already in sys.path.
+- # Otherwise trying to import the extensions after building them
+- # will fail.
+- with open(_BUILDDIR_COOKIE, "wb") as f:
+- f.write(self.build_lib.encode('utf-8', 'surrogateescape'))
++ # We manually install the shared modules directory if it isn't
++ # already in sys.path. Otherwise trying to import the
++ # extensions after building them will fail.
+ abs_build_lib = os.path.join(os.getcwd(), self.build_lib)
+ if abs_build_lib not in sys.path:
+ sys.path.append(abs_build_lib)
+
diff --git a/debian/patches/tempfile-minimal.diff b/debian/patches/tempfile-minimal.diff
new file mode 100644
index 0000000..5299715
--- /dev/null
+++ b/debian/patches/tempfile-minimal.diff
@@ -0,0 +1,169 @@
+# DP: Avoid shutil import when it is not available.
+
+Index: b/Lib/tempfile.py
+===================================================================
+--- a/Lib/tempfile.py
++++ b/Lib/tempfile.py
+@@ -40,7 +40,146 @@ import functools as _functools
+ import warnings as _warnings
+ import io as _io
+ import os as _os
+-import shutil as _shutil
++try:
++ import shutil as _shutil
++ _rmtree = _shutil.rmtree
++except ImportError:
++ import sys as _sys
++ import stat as _stat
++ # version vulnerable to race conditions
++ def _rmtree_unsafe(path, onerror):
++ try:
++ if _os.path.islink(path):
++ # symlinks to directories are forbidden, see bug #1669
++ raise OSError("Cannot call rmtree on a symbolic link")
++ except OSError:
++ onerror(_os.path.islink, path, _sys.exc_info())
++ # can't continue even if onerror hook returns
++ return
++ names = []
++ try:
++ names = _os.listdir(path)
++ except OSError:
++ onerror(_os.listdir, path, _sys.exc_info())
++ for name in names:
++ fullname = _os.path.join(path, name)
++ try:
++ mode = _os.lstat(fullname).st_mode
++ except OSError:
++ mode = 0
++ if _stat.S_ISDIR(mode):
++ _rmtree_unsafe(fullname, onerror)
++ else:
++ try:
++ _os.unlink(fullname)
++ except OSError:
++ onerror(_os.unlink, fullname, _sys.exc_info())
++ try:
++ _os.rmdir(path)
++ except OSError:
++ onerror(_os.rmdir, path, _sys.exc_info())
++
++ # Version using fd-based APIs to protect against races
++ def _rmtree_safe_fd(topfd, path, onerror):
++ names = []
++ try:
++ names = _os.listdir(topfd)
++ except OSError as err:
++ err.filename = path
++ onerror(_os.listdir, path, _sys.exc_info())
++ for name in names:
++ fullname = _os.path.join(path, name)
++ try:
++ orig_st = _os.stat(name, dir_fd=topfd, follow_symlinks=False)
++ mode = orig_st.st_mode
++ except OSError:
++ mode = 0
++ if _stat.S_ISDIR(mode):
++ try:
++ dirfd = _os.open(name, _os.O_RDONLY, dir_fd=topfd)
++ except OSError:
++ onerror(_os.open, fullname, _sys.exc_info())
++ else:
++ try:
++ if _os.path.samestat(orig_st, _os.fstat(dirfd)):
++ _rmtree_safe_fd(dirfd, fullname, onerror)
++ try:
++ _os.rmdir(name, dir_fd=topfd)
++ except OSError:
++ onerror(_os.rmdir, fullname, _sys.exc_info())
++ else:
++ try:
++ # This can only happen if someone replaces
++ # a directory with a symlink after the call to
++ # stat.S_ISDIR above.
++ raise OSError("Cannot call rmtree on a symbolic "
++ "link")
++ except OSError:
++ onerror(_os.path.islink, fullname, _sys.exc_info())
++ finally:
++ _os.close(dirfd)
++ else:
++ try:
++ _os.unlink(name, dir_fd=topfd)
++ except OSError:
++ onerror(_os.unlink, fullname, _sys.exc_info())
++
++ _use_fd_functions = ({_os.open, _os.stat, _os.unlink, _os.rmdir} <=
++ _os.supports_dir_fd and
++ _os.listdir in _os.supports_fd and
++ _os.stat in _os.supports_follow_symlinks)
++
++ def _rmtree(path, ignore_errors=False, onerror=None):
++ """Recursively delete a directory tree.
++
++ If ignore_errors is set, errors are ignored; otherwise, if onerror
++ is set, it is called to handle the error with arguments (func,
++ path, exc_info) where func is platform and implementation dependent;
++ path is the argument to that function that caused it to fail; and
++ exc_info is a tuple returned by sys.exc_info(). If ignore_errors
++ is false and onerror is None, an exception is raised.
++
++ """
++ if ignore_errors:
++ def onerror(*args):
++ pass
++ elif onerror is None:
++ def onerror(*args):
++ raise
++ if _use_fd_functions:
++ # While the unsafe rmtree works fine on bytes, the fd based does not.
++ if isinstance(path, bytes):
++ path = _os.fsdecode(path)
++ # Note: To guard against symlink races, we use the standard
++ # lstat()/open()/fstat() trick.
++ try:
++ orig_st = _os.lstat(path)
++ except Exception:
++ onerror(_os.lstat, path, _sys.exc_info())
++ return
++ try:
++ fd = _os.open(path, _os.O_RDONLY)
++ except Exception:
++ onerror(_os.lstat, path, _sys.exc_info())
++ return
++ try:
++ if _os.path.samestat(orig_st, _os.fstat(fd)):
++ _rmtree_safe_fd(fd, path, onerror)
++ try:
++ _os.rmdir(path)
++ except OSError:
++ onerror(_os.rmdir, path, _sys.exc_info())
++ else:
++ try:
++ # symlinks to directories are forbidden, see bug #1669
++ raise OSError("Cannot call rmtree on a symbolic link")
++ except OSError:
++ onerror(_os.path.islink, path, _sys.exc_info())
++ finally:
++ _os.close(fd)
++ else:
++ return _rmtree_unsafe(path, onerror)
++
+ import errno as _errno
+ from random import Random as _Random
+ import weakref as _weakref
+@@ -794,7 +933,7 @@ class TemporaryDirectory(object):
+
+ @classmethod
+ def _cleanup(cls, name, warn_message):
+- _shutil.rmtree(name)
++ _rmtree(name)
+ _warnings.warn(warn_message, ResourceWarning)
+
+
+@@ -809,4 +948,4 @@ class TemporaryDirectory(object):
+
+ def cleanup(self):
+ if self._finalizer.detach():
+- _shutil.rmtree(self.name)
++ _rmtree(self.name)
diff --git a/debian/patches/test-no-random-order.diff b/debian/patches/test-no-random-order.diff
new file mode 100644
index 0000000..1c98695
--- /dev/null
+++ b/debian/patches/test-no-random-order.diff
@@ -0,0 +1,14 @@
+# DP: Don't run the test suite in random order.
+
+Index: b/Tools/scripts/run_tests.py
+===================================================================
+--- a/Tools/scripts/run_tests.py
++++ b/Tools/scripts/run_tests.py
+@@ -37,7 +37,6 @@ def main(regrtest_args):
+ args.extend(['-W', 'error::BytesWarning'])
+
+ args.extend(['-m', 'test', # Run the test suite
+- '-r', # Randomize test order
+ '-w', # Re-run failed tests in verbose mode
+ ])
+ if sys.platform == 'win32':
diff --git a/debian/patches/tkinter-import.diff b/debian/patches/tkinter-import.diff
new file mode 100644
index 0000000..81673e6
--- /dev/null
+++ b/debian/patches/tkinter-import.diff
@@ -0,0 +1,18 @@
+# DP: suggest installation of python-tk package on failing _tkinter import
+
+Index: b/Lib/tkinter/__init__.py
+===================================================================
+--- a/Lib/tkinter/__init__.py
++++ b/Lib/tkinter/__init__.py
+@@ -32,7 +32,10 @@ tk.mainloop()
+
+ import sys
+
+-import _tkinter # If this fails your Python may not be configured for Tk
++try:
++ import _tkinter
++except ImportError as msg:
++ raise ImportError(str(msg) + ', please install the python3-tk package')
+ TclError = _tkinter.TclError
+ from tkinter.constants import *
+ import re