summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉric Araujo <merwok@netwok.org>2011-07-29 14:30:03 +0200
committerÉric Araujo <merwok@netwok.org>2011-07-29 14:30:03 +0200
commit0bbacc621c0d844e24ea8e9ff84e35883af6678b (patch)
tree4db1983004caa59b7d56765118d9973ca6d41f79
parentabe9dc3f30b9166e2c4c9c5e21a235ec655a6ca0 (diff)
parentbab50cb1247f79d10a746ec4dae88848319ff162 (diff)
downloadcpython-git-0bbacc621c0d844e24ea8e9ff84e35883af6678b.tar.gz
Branch merge
-rw-r--r--.bzrignore1
-rw-r--r--.gitignore1
-rw-r--r--.hgignore3
-rw-r--r--Doc/ACKS.txt1
-rw-r--r--Doc/distutils/apiref.rst4
-rw-r--r--Doc/distutils/install.rst2
-rw-r--r--Doc/glossary.rst3
-rw-r--r--Doc/library/ossaudiodev.rst2
-rw-r--r--Doc/library/packaging.dist.rst4
-rw-r--r--Doc/library/profile.rst26
-rw-r--r--Doc/library/shlex.rst19
-rw-r--r--Doc/library/shutil.rst26
-rw-r--r--Doc/library/subprocess.rst7
-rw-r--r--Doc/license.rst30
-rw-r--r--Doc/tools/sphinxext/susp-ignored.csv2
-rw-r--r--Doc/tutorial/classes.rst28
-rw-r--r--Doc/whatsnew/3.3.rst4
-rw-r--r--Lib/modulefinder.py15
-rw-r--r--Lib/multiprocessing/dummy/__init__.py13
-rw-r--r--Lib/packaging/command/cmd.py3
-rw-r--r--Lib/packaging/database.py2
-rw-r--r--Lib/packaging/depgraph.py4
-rw-r--r--Lib/packaging/install.py24
-rw-r--r--Lib/packaging/run.py70
-rw-r--r--Lib/packaging/tests/test_database.py10
-rw-r--r--Lib/packaging/tests/test_install.py2
-rw-r--r--Lib/pipes.py23
-rw-r--r--Lib/pstats.py4
-rw-r--r--Lib/shlex.py20
-rw-r--r--Lib/test/list_tests.py16
-rw-r--r--Lib/test/test_modulefinder.py48
-rw-r--r--Lib/test/test_pipes.py14
-rw-r--r--Lib/test/test_shlex.py20
-rw-r--r--Lib/test/test_sort.py23
-rw-r--r--Lib/threading.py29
-rw-r--r--Misc/NEWS10
-rw-r--r--Python/marshal.c6
-rwxr-xr-x[-rw-r--r--]Tools/scripts/abitype.py1
-rwxr-xr-x[-rw-r--r--]Tools/scripts/cleanfuture.py0
-rwxr-xr-x[-rw-r--r--]Tools/scripts/combinerefs.py0
-rwxr-xr-x[-rw-r--r--]Tools/scripts/db2pickle.py0
-rwxr-xr-x[-rw-r--r--]Tools/scripts/diff.py1
-rwxr-xr-x[-rw-r--r--]Tools/scripts/find_recursionlimit.py0
-rwxr-xr-x[-rw-r--r--]Tools/scripts/get-remote-certificate.py0
-rwxr-xr-x[-rw-r--r--]Tools/scripts/mailerdaemon.py25
-rwxr-xr-x[-rw-r--r--]Tools/scripts/make_ctype.py1
-rwxr-xr-x[-rw-r--r--]Tools/scripts/md5sum.py0
-rwxr-xr-x[-rw-r--r--]Tools/scripts/patchcheck.py1
-rwxr-xr-x[-rw-r--r--]Tools/scripts/pickle2db.py0
-rwxr-xr-x[-rw-r--r--]Tools/scripts/pysource.py0
-rwxr-xr-xTools/scripts/reindent-rst.py2
-rwxr-xr-x[-rw-r--r--]Tools/scripts/svneol.py0
52 files changed, 256 insertions, 294 deletions
diff --git a/.bzrignore b/.bzrignore
index e893a7dfcf..959a7df6ed 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -14,6 +14,7 @@ platform
pybuilddir.txt
pyconfig.h
libpython*.a
+libpython*.so*
python.exe
python-gdb.py
reflog.txt
diff --git a/.gitignore b/.gitignore
index 63f4314e05..da0ca02d7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@ build/
config.log
config.status
libpython*.a
+libpython*.so*
pybuilddir.txt
pyconfig.h
python
diff --git a/.hgignore b/.hgignore
index 6a2615b94b..3919a03c87 100644
--- a/.hgignore
+++ b/.hgignore
@@ -41,14 +41,13 @@ PCbuild/amd64/
syntax: glob
libpython*.a
+libpython*.so*
*.swp
*.o
*.pyc
*.pyo
*.pyd
*.cover
-*.orig
-*.rej
*~
Lib/lib2to3/*.pickle
Lib/test/data/*
diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt
index 433c9ee3a4..5faa7069e8 100644
--- a/Doc/ACKS.txt
+++ b/Doc/ACKS.txt
@@ -203,6 +203,7 @@ docs@python.org), and we'll be glad to correct the problem.
* Kalle Svensson
* Jim Tittsler
* David Turner
+ * Sandro Tosi
* Ville Vainio
* Nadeem Vawda
* Martijn Vries
diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst
index 1fb6f9e45f..124d891a49 100644
--- a/Doc/distutils/apiref.rst
+++ b/Doc/distutils/apiref.rst
@@ -72,8 +72,8 @@ setup script). Indirectly provides the :class:`distutils.dist.Distribution` and
| | be built | :class:`distutils.core.Extension` |
+--------------------+--------------------------------+-------------------------------------------------------------+
| *classifiers* | A list of categories for the | The list of available |
- | | package | categorizations is at |
- | | | http://pypi.python.org/pypi?:action=list_classifiers. |
+ | | package | categorizations is available on `PyPI |
+ | | | <http://pypi.python.org/pypi?:action=list_classifiers>`_. |
+--------------------+--------------------------------+-------------------------------------------------------------+
| *distclass* | the :class:`Distribution` | A subclass of |
| | class to use | :class:`distutils.core.Distribution` |
diff --git a/Doc/distutils/install.rst b/Doc/distutils/install.rst
index f8d63057a6..6f4de7a37d 100644
--- a/Doc/distutils/install.rst
+++ b/Doc/distutils/install.rst
@@ -72,7 +72,7 @@ In that case, you would download the installer appropriate to your platform and
do the obvious thing with it: run it if it's an executable installer, ``rpm
--install`` it if it's an RPM, etc. You don't need to run Python or a setup
script, you don't need to compile anything---you might not even need to read any
-instructions (although it's always a good idea to do so anyways).
+instructions (although it's always a good idea to do so anyway).
Of course, things will not always be that easy. You might be interested in a
module distribution that doesn't have an easy-to-use installer for your
diff --git a/Doc/glossary.rst b/Doc/glossary.rst
index 2961af1df0..6984bf2098 100644
--- a/Doc/glossary.rst
+++ b/Doc/glossary.rst
@@ -431,7 +431,8 @@ Glossary
mapping
A container object that supports arbitrary key lookups and implements the
- methods specified in the :class:`Mapping` or :class:`MutableMapping`
+ methods specified in the :class:`~collections.Mapping` or
+ :class:`~collections.MutableMapping`
:ref:`abstract base classes <collections-abstract-base-classes>`. Examples
include :class:`dict`, :class:`collections.defaultdict`,
:class:`collections.OrderedDict` and :class:`collections.Counter`.
diff --git a/Doc/library/ossaudiodev.rst b/Doc/library/ossaudiodev.rst
index 3b5a7e4212..0a08428409 100644
--- a/Doc/library/ossaudiodev.rst
+++ b/Doc/library/ossaudiodev.rst
@@ -14,7 +14,7 @@ the standard audio interface for Linux and recent versions of FreeBSD.
ALSA is in the standard kernel as of 2.5.x. Presumably if you
use ALSA, you'll have to make sure its OSS compatibility layer
is active to use ossaudiodev, but you're gonna need it for the vast
- majority of Linux audio apps anyways.
+ majority of Linux audio apps anyway.
Sounds like things are also complicated for other BSDs. In response
to my python-dev query, Thomas Wouters said:
diff --git a/Doc/library/packaging.dist.rst b/Doc/library/packaging.dist.rst
index fb05b69c70..7184f7fcaa 100644
--- a/Doc/library/packaging.dist.rst
+++ b/Doc/library/packaging.dist.rst
@@ -67,8 +67,8 @@ module distribution being built/packaged/distributed/installed.
| | be built | :class:`packaging.compiler.extension.Extension` |
+--------------------+--------------------------------+-------------------------------------------------------------+
| *classifiers* | A list of categories for the | The list of available |
- | | distribution | categorizations is at |
- | | | http://pypi.python.org/pypi?:action=list_classifiers. |
+ | | distribution | categorizations is available on `PyPI |
+ | | | <http://pypi.python.org/pypi?:action=list_classifiers>`_. |
+--------------------+--------------------------------+-------------------------------------------------------------+
| *distclass* | the :class:`Distribution` | A subclass of |
| | class to use | :class:`packaging.dist.Distribution` |
diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst
index 3931836f70..ca54021630 100644
--- a/Doc/library/profile.rst
+++ b/Doc/library/profile.rst
@@ -39,7 +39,7 @@ The Python standard library provides two different profilers:
2. :mod:`profile`, a pure Python module whose interface is imitated by
:mod:`cProfile`. Adds significant overhead to profiled programs. If you're
trying to extend the profiler in some way, the task might be easier with this
- module. Copyright © 1994, by InfoSeek Corporation.
+ module.
The :mod:`profile` and :mod:`cProfile` modules export the same interface, so
they are mostly interchangeable; :mod:`cProfile` has a much lower overhead but
@@ -592,27 +592,3 @@ The resulting profiler will then call :func:`your_time_func`.
functions should be used with care and should be as fast as possible. For the
best results with a custom timer, it might be necessary to hard-code it in the C
source of the internal :mod:`_lsprof` module.
-
-
-Copyright and License Notices
-=============================
-
-Copyright © 1994, by InfoSeek Corporation, all rights reserved.
-
-Permission to use, copy, modify, and distribute this Python software and its
-associated documentation for any purpose (subject to the restriction in the
-following sentence) without fee is hereby granted, provided that the above
-copyright notice appears in all copies, and that both that copyright notice and
-this permission notice appear in supporting documentation, and that the name of
-InfoSeek not be used in advertising or publicity pertaining to distribution of
-the software without specific, written prior permission. This permission is
-explicitly restricted to the copying and modification of the software to remain
-in Python, compiled Python, or other languages (such as C) wherein the modified
-or derived code is exclusively imported into a Python module.
-
-INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT
-SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
-DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst
index 0113fb7db3..e5aec4a936 100644
--- a/Doc/library/shlex.rst
+++ b/Doc/library/shlex.rst
@@ -34,6 +34,22 @@ The :mod:`shlex` module defines the following functions:
passing ``None`` for *s* will read the string to split from standard
input.
+
+.. function:: quote(s)
+
+ Return a shell-escaped version of the string *s*. The returned value is a
+ string that can safely be used as one token in a shell command line.
+ Examples::
+
+ >>> filename = 'somefile; rm -rf /home'
+ >>> command = 'ls -l {}'.format(quote(filename))
+ >>> print(command)
+ ls -l 'somefile; rm -rf /home'
+ >>> remote_command = 'ssh home {}'.format(quote(command))
+ >>> print(remote_command)
+ ssh home 'ls -l '"'"'somefile; rm -rf /home'"'"''
+
+
The :mod:`shlex` module defines the following class:
@@ -282,5 +298,4 @@ parsing rules.
* EOF is signaled with a :const:`None` value;
-* Quoted empty strings (``''``) are allowed;
-
+* Quoted empty strings (``''``) are allowed.
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst
index f8a1b60f6f..799230cdd9 100644
--- a/Doc/library/shutil.rst
+++ b/Doc/library/shutil.rst
@@ -159,12 +159,18 @@ Directory and files operations
.. function:: move(src, dst)
- Recursively move a file or directory to another location.
+ Recursively move a file or directory (*src*) to another location (*dst*).
- Uses :func:`os.rename` to perform the move. If it fails, for reasons such as
- when *src* and *dst* are on different filesystems or in case of windows where
- rename is not supported when *dst* exists, fallback to copying *src* (with
- :func:`copy2`) to the *dst* and then remove *src*.
+ If the destination is a directory or a symlink to a directory, then *src* is
+ moved inside that directory.
+
+ The destination directory must not already exist. If the destination already
+ exists but is not a directory, it may be overwritten depending on
+ :func:`os.rename` semantics.
+
+ If the destination is on the current filesystem, then :func:`os.rename` is
+ used. Otherwise, *src* is copied (using :func:`copy2`) to *dst* and then
+ removed.
.. function:: disk_usage(path)
@@ -177,9 +183,9 @@ Directory and files operations
.. exception:: Error
- This exception collects exceptions that raised during a multi-file operation. For
- :func:`copytree`, the exception argument is a list of 3-tuples (*srcname*,
- *dstname*, *exception*).
+ This exception collects exceptions that are raised during a multi-file
+ operation. For :func:`copytree`, the exception argument is a list of 3-tuples
+ (*srcname*, *dstname*, *exception*).
.. _shutil-example:
@@ -277,7 +283,7 @@ Archiving operations
.. function:: get_archive_formats()
- Returns a list of supported formats for archiving.
+ Return a list of supported formats for archiving.
Each element of the returned sequence is a tuple ``(name, description)``
By default :mod:`shutil` provides these formats:
@@ -295,7 +301,7 @@ Archiving operations
.. function:: register_archive_format(name, function, [extra_args, [description]])
- Registers an archiver for the format *name*. *function* is a callable that
+ Register an archiver for the format *name*. *function* is a callable that
will be used to invoke the archiver.
If given, *extra_args* is a sequence of ``(name, value)`` pairs that will be
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index 7e759f0d03..2c7613027b 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -92,7 +92,8 @@ This module defines one class called :class:`Popen`:
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...
*shell=False* does not suffer from this vulnerability; the above Note may be
- helpful in getting code using *shell=False* to work.
+ helpful in getting code using *shell=False* to work. See also
+ :func:`shlex.quote` for a function useful to quote filenames and commands.
On Windows: the :class:`Popen` class uses CreateProcess() to execute the
child program, which operates on strings. If *args* is a sequence, it will
@@ -871,3 +872,7 @@ runtime):
described in rule 3.
+.. seealso::
+
+ :mod:`shlex`
+ Module which provides function to parse and escape command lines.
diff --git a/Doc/license.rst b/Doc/license.rst
index 615b18cef7..d0b370fa58 100644
--- a/Doc/license.rst
+++ b/Doc/license.rst
@@ -494,36 +494,6 @@ The :mod:`http.cookies` module contains the following notice::
PERFORMANCE OF THIS SOFTWARE.
-Profiling
----------
-
-The :mod:`profile` and :mod:`pstats` modules contain the following notice::
-
- Copyright 1994, by InfoSeek Corporation, all rights reserved.
- Written by James Roskind
-
- Permission to use, copy, modify, and distribute this Python software
- and its associated documentation for any purpose (subject to the
- restriction in the following sentence) without fee is hereby granted,
- provided that the above copyright notice appears in all copies, and
- that both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of InfoSeek not be used in
- advertising or publicity pertaining to distribution of the software
- without specific, written prior permission. This permission is
- explicitly restricted to the copying and modification of the software
- to remain in Python, compiled Python, or other languages (such as C)
- wherein the modified or derived code is exclusively imported into a
- Python module.
-
- INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
- SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
Execution tracing
-----------------
diff --git a/Doc/tools/sphinxext/susp-ignored.csv b/Doc/tools/sphinxext/susp-ignored.csv
index 57d2f9c63b..8211d62721 100644
--- a/Doc/tools/sphinxext/susp-ignored.csv
+++ b/Doc/tools/sphinxext/susp-ignored.csv
@@ -5,7 +5,6 @@ c-api/sequence,,:i2,o[i1:i2]
c-api/sequence,,:i2,o[i1:i2] = v
c-api/sequence,,:i2,del o[i1:i2]
c-api/unicode,,:end,str[start:end]
-distutils/apiref,,:action,http://pypi.python.org/pypi?:action=list_classifiers
distutils/setupscript,,::,
extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))"
extending/extending,,:set,"if (PyArg_ParseTuple(args, ""O:set_callback"", &temp)) {"
@@ -495,7 +494,6 @@ library/pprint,209,::,"'Programming Language :: Python :: 2.6',"
library/pprint,209,::,"'Programming Language :: Python :: 2.7',"
library/pprint,209,::,"'Topic :: Software Development :: Libraries',"
library/pprint,209,::,"'Topic :: Software Development :: Libraries :: Python Modules'],"
-library/packaging.dist,,:action,http://pypi.python.org/pypi?:action=list_classifiers
packaging/examples,,`,This is the description of the ``foobar`` project.
packaging/setupcfg,,::,Development Status :: 3 - Alpha
packaging/setupcfg,,::,License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)
diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst
index 336d0740dd..4926280aa6 100644
--- a/Doc/tutorial/classes.rst
+++ b/Doc/tutorial/classes.rst
@@ -598,24 +598,24 @@ occurs within the definition of a class.
Name mangling is helpful for letting subclasses override methods without
breaking intraclass method calls. For example::
- class Mapping:
- def __init__(self, iterable):
- self.items_list = []
- self.__update(iterable)
+ class Mapping:
+ def __init__(self, iterable):
+ self.items_list = []
+ self.__update(iterable)
- def update(self, iterable):
- for item in iterable:
- self.items_list.append(item)
+ def update(self, iterable):
+ for item in iterable:
+ self.items_list.append(item)
- __update = update # private copy of original update() method
+ __update = update # private copy of original update() method
- class MappingSubclass(Mapping):
+ class MappingSubclass(Mapping):
- def update(self, keys, values):
- # provides new signature for update()
- # but does not break __init__()
- for item in zip(keys, values):
- self.items_list.append(item)
+ def update(self, keys, values):
+ # provides new signature for update()
+ # but does not break __init__()
+ for item in zip(keys, values):
+ self.items_list.append(item)
Note that the mangling rules are designed mostly to avoid accidents; it still is
possible to access or modify a variable that is considered private. This can
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
index 677f35cde4..79a53ff31e 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -94,8 +94,8 @@ versions.
curses
------
-The :class:`curses.window` class has a new :class:`~curses.window.get_wch`
-method to a wide character. Patch by Iñigo Serna.
+The :class:`curses.window` class has a new :meth:`~curses.window.get_wch` method
+to get a wide character. Patch by Iñigo Serna.
(:issue:`6755`)
diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py
index f033ba98ef..da5b56d84c 100644
--- a/Lib/modulefinder.py
+++ b/Lib/modulefinder.py
@@ -1,6 +1,5 @@
"""Find modules used by a script, using introspection."""
-from __future__ import generators
import dis
import imp
import marshal
@@ -9,8 +8,6 @@ import sys
import types
import struct
-READ_MODE = "rU"
-
# XXX Clean up once str8's cstor matches bytes.
LOAD_CONST = bytes([dis.opname.index('LOAD_CONST')])
IMPORT_NAME = bytes([dis.opname.index('IMPORT_NAME')])
@@ -29,8 +26,7 @@ packagePathMap = {}
# A Public interface
def AddPackagePath(packagename, path):
- paths = packagePathMap.get(packagename, [])
- paths.append(path)
+ paths = packagePathMap.setdefault(packagename, []).append(path)
packagePathMap[packagename] = paths
replacePackageMap = {}
@@ -106,14 +102,14 @@ class ModuleFinder:
def run_script(self, pathname):
self.msg(2, "run_script", pathname)
- with open(pathname, READ_MODE) as fp:
+ with open(pathname) as fp:
stuff = ("", "r", imp.PY_SOURCE)
self.load_module('__main__', fp, pathname, stuff)
def load_file(self, pathname):
dir, name = os.path.split(pathname)
name, ext = os.path.splitext(name)
- with open(pathname, READ_MODE) as fp:
+ with open(pathname) as fp:
stuff = (ext, "r", imp.PY_SOURCE)
self.load_module(name, fp, pathname, stuff)
@@ -270,7 +266,8 @@ class ModuleFinder:
try:
m = self.load_module(fqname, fp, pathname, stuff)
finally:
- if fp: fp.close()
+ if fp:
+ fp.close()
if parent:
setattr(parent, partname, m)
self.msgout(3, "import_module ->", m)
@@ -662,4 +659,4 @@ if __name__ == '__main__':
try:
mf = test()
except KeyboardInterrupt:
- print("\n[interrupt]")
+ print("\n[interrupted]")
diff --git a/Lib/multiprocessing/dummy/__init__.py b/Lib/multiprocessing/dummy/__init__.py
index c4933d9ec5..60add922bf 100644
--- a/Lib/multiprocessing/dummy/__init__.py
+++ b/Lib/multiprocessing/dummy/__init__.py
@@ -51,7 +51,7 @@ import itertools
from multiprocessing import TimeoutError, cpu_count
from multiprocessing.dummy.connection import Pipe
from threading import Lock, RLock, Semaphore, BoundedSemaphore
-from threading import Event
+from threading import Event, Condition
from queue import Queue
#
@@ -84,17 +84,6 @@ class DummyProcess(threading.Thread):
#
#
-class Condition(threading._Condition):
- # XXX
- if sys.version_info < (3, 0):
- notify_all = threading._Condition.notify_all.__func__
- else:
- notify_all = threading._Condition.notify_all
-
-#
-#
-#
-
Process = DummyProcess
current_process = threading.current_thread
current_process()._children = weakref.WeakKeyDictionary()
diff --git a/Lib/packaging/command/cmd.py b/Lib/packaging/command/cmd.py
index fa56aa63f6..1053ac390a 100644
--- a/Lib/packaging/command/cmd.py
+++ b/Lib/packaging/command/cmd.py
@@ -57,7 +57,8 @@ class Command:
from packaging.dist import Distribution
if not isinstance(dist, Distribution):
- raise TypeError("dist must be a Distribution instance")
+ raise TypeError("dist must be an instance of Distribution, not %r"
+ % type(dist))
if self.__class__ is Command:
raise RuntimeError("Command is an abstract class")
diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py
index c1bd729b6d..0aaa0cdc91 100644
--- a/Lib/packaging/database.py
+++ b/Lib/packaging/database.py
@@ -351,7 +351,7 @@ class EggInfoDistribution:
except IOError:
requires = None
self.metadata = Metadata(path=path)
- self.name = self.metadata['name']
+ self.name = self.metadata['Name']
self.version = self.metadata['Version']
else:
diff --git a/Lib/packaging/depgraph.py b/Lib/packaging/depgraph.py
index b3c555a8a2..843aab47b0 100644
--- a/Lib/packaging/depgraph.py
+++ b/Lib/packaging/depgraph.py
@@ -72,7 +72,7 @@ class DependencyGraph:
self.missing[distribution].append(requirement)
def _repr_dist(self, dist):
- return '%r %s' % (dist.name, dist.metadata['Version'])
+ return '%r %s' % (dist.name, dist.version)
def repr_node(self, dist, level=1):
"""Prints only a subgraph"""
@@ -145,7 +145,7 @@ def generate_graph(dists):
graph.add_distribution(dist)
provides = (dist.metadata['Provides-Dist'] +
dist.metadata['Provides'] +
- ['%s (%s)' % (dist.name, dist.metadata['Version'])])
+ ['%s (%s)' % (dist.name, dist.version)])
for p in provides:
comps = p.strip().rsplit(" ", 1)
diff --git a/Lib/packaging/install.py b/Lib/packaging/install.py
index 51e70df427..b6816e56b2 100644
--- a/Lib/packaging/install.py
+++ b/Lib/packaging/install.py
@@ -85,7 +85,7 @@ def _run_packaging_install(path):
dist.parse_config_files()
try:
dist.run_command('install_dist')
- name = dist.metadata['name']
+ name = dist.metadata['Name']
return database.get_distribution(name) is not None
except (IOError, os.error, PackagingError, CCompilerError) as msg:
raise ValueError("Failed to install, " + str(msg))
@@ -118,10 +118,10 @@ def install_local_project(path):
"""
path = os.path.abspath(path)
if os.path.isdir(path):
- logger.info('Installing from source directory: %s', path)
+ logger.info('Installing from source directory: %r', path)
return _run_install_from_dir(path)
elif _is_archive_file(path):
- logger.info('Installing from archive: %s', path)
+ logger.info('Installing from archive: %r', path)
_unpacked_dir = tempfile.mkdtemp()
try:
shutil.unpack_archive(path, _unpacked_dir)
@@ -129,7 +129,7 @@ def install_local_project(path):
finally:
shutil.rmtree(_unpacked_dir)
else:
- logger.warning('No projects to install.')
+ logger.warning('No project to install.')
return False
@@ -191,7 +191,7 @@ def install_dists(dists, path, paths=None):
# reverting
for installed_dist in installed_dists:
- logger.info('Reverting %s', installed_dist)
+ logger.info('Reverting %r', installed_dist)
remove(installed_dist.name, paths)
raise e
return installed_dists
@@ -314,12 +314,12 @@ def get_infos(requirements, index=None, installed=None, prefer_final=True):
if predicate.name.lower() != installed_project.name.lower():
continue
found = True
- logger.info('Found %s %s', installed_project.name,
- installed_project.metadata['version'])
+ logger.info('Found %r %s', installed_project.name,
+ installed_project.version)
# if we already have something installed, check it matches the
# requirements
- if predicate.match(installed_project.metadata['version']):
+ if predicate.match(installed_project.version):
return infos
break
@@ -336,7 +336,7 @@ def get_infos(requirements, index=None, installed=None, prefer_final=True):
try:
release = index.get_release(requirements)
except (ReleaseNotFound, ProjectNotFound):
- raise InstallationException('Release not found: "%s"' % requirements)
+ raise InstallationException('Release not found: %r' % requirements)
if release is None:
logger.info('Could not find a matching project')
@@ -386,7 +386,7 @@ def remove(project_name, paths=None, auto_confirm=True):
"""
dist = get_distribution(project_name, use_egg_info=True, paths=paths)
if dist is None:
- raise PackagingError('Distribution "%s" not found' % project_name)
+ raise PackagingError('Distribution %r not found' % project_name)
files = dist.list_installed_files(local=True)
rmdirs = []
rmfiles = []
@@ -423,7 +423,7 @@ def remove(project_name, paths=None, auto_confirm=True):
if not success:
logger.info('%r cannot be removed.', project_name)
- logger.info('Error: %s' % str(error))
+ logger.info('Error: %s', error)
return False
logger.info('Removing %r: ', project_name)
@@ -523,7 +523,7 @@ def install(project):
except InstallationConflict as e:
if logger.isEnabledFor(logging.INFO):
- projects = ['%r %s' % (p.name, p.version) for p in e.args[0]]
+ projects = ('%r %s' % (p.name, p.version) for p in e.args[0])
logger.info('%r conflicts with %s', project, ','.join(projects))
return True
diff --git a/Lib/packaging/run.py b/Lib/packaging/run.py
index 3e720cf7e8..8e117ed36b 100644
--- a/Lib/packaging/run.py
+++ b/Lib/packaging/run.py
@@ -214,7 +214,7 @@ def _create(distpatcher, args, **kw):
@action_help(generate_usage)
def _generate(distpatcher, args, **kw):
generate_setup_py()
- print('The setup.py was generated')
+ logger.info('The setup.py was generated')
@action_help(graph_usage)
@@ -222,7 +222,8 @@ def _graph(dispatcher, args, **kw):
name = args[1]
dist = get_distribution(name, use_egg_info=True)
if dist is None:
- print('Distribution not found.')
+ logger.warning('Distribution not found.')
+ return 1
else:
dists = get_distributions(use_egg_info=True)
graph = generate_graph(dists)
@@ -234,8 +235,7 @@ def _install(dispatcher, args, **kw):
# first check if we are in a source directory
if len(args) < 2:
# are we inside a project dir?
- listing = os.listdir(os.getcwd())
- if 'setup.py' in listing or 'setup.cfg' in listing:
+ if os.path.isfile('setup.cfg') or os.path.isfile('setup.py'):
args.insert(1, os.getcwd())
else:
logger.warning('No project to install.')
@@ -244,16 +244,10 @@ def _install(dispatcher, args, **kw):
target = args[1]
# installing from a source dir or archive file?
if os.path.isdir(target) or _is_archive_file(target):
- if install_local_project(target):
- return 0
- else:
- return 1
+ return not install_local_project(target)
else:
# download from PyPI
- if install(target):
- return 0
- else:
- return 1
+ return not install(target)
@action_help(metadata_usage)
@@ -263,12 +257,15 @@ def _metadata(dispatcher, args, **kw):
name = opts['args'][0]
dist = get_distribution(name, use_egg_info=True)
if dist is None:
- logger.warning('%s not installed', name)
- return
- else:
+ logger.warning('%r not installed', name)
+ return 1
+ elif os.path.isfile('setup.cfg'):
logger.info('searching local dir for metadata')
- dist = Distribution()
+ dist = Distribution() # XXX use config module
dist.parse_config_files()
+ else:
+ logger.warning('no argument given and no local setup.cfg found')
+ return 1
metadata = dist.metadata
@@ -299,11 +296,15 @@ def _remove(distpatcher, args, **kw):
else:
auto_confirm = False
+ retcode = 0
for dist in set(opts['args']):
try:
remove(dist, auto_confirm=auto_confirm)
except PackagingError:
- logger.warning('%s not installed', dist)
+ logger.warning('%r not installed', dist)
+ retcode = 1
+
+ return retcode
@action_help(run_usage)
@@ -339,14 +340,8 @@ def _run(dispatcher, args, **kw):
# XXX still need to be extracted from Distribution
dist.parse_config_files()
- try:
- for cmd in dispatcher.commands:
- dist.run_command(cmd, dispatcher.command_options[cmd])
-
- except KeyboardInterrupt:
- raise SystemExit("interrupted")
- except (IOError, os.error, PackagingError, CCompilerError) as msg:
- raise SystemExit("error: " + str(msg))
+ for cmd in dispatcher.commands:
+ dist.run_command(cmd, dispatcher.command_options[cmd])
# XXX this is crappy
return dist
@@ -358,19 +353,24 @@ def _list(dispatcher, args, **kw):
dists = get_distributions(use_egg_info=True)
if 'all' in opts or opts['args'] == []:
results = dists
+ listall = True
else:
- results = [d for d in dists if d.name.lower() in opts['args']]
+ results = (d for d in dists if d.name.lower() in opts['args'])
+ listall = False
number = 0
for dist in results:
- print('%s %s at %s' % (dist.name, dist.metadata['version'], dist.path))
+ print('%r %s (from %r)' % (dist.name, dist.version, dist.path))
number += 1
- print()
if number == 0:
- print('Nothing seems to be installed.')
+ if listall:
+ logger.info('Nothing seems to be installed.')
+ else:
+ logger.warning('No matching distribution found.')
+ return 1
else:
- print('Found %d projects installed.' % number)
+ logger.info('Found %d projects installed.', number)
@action_help(search_usage)
@@ -382,7 +382,8 @@ def _search(dispatcher, args, **kw):
"""
#opts = _parse_args(args[1:], '', ['simple', 'xmlrpc'])
# 1. what kind of index is requested ? (xmlrpc / simple)
- raise NotImplementedError
+ logger.error('not implemented')
+ return 1
actions = [
@@ -662,6 +663,7 @@ class Dispatcher:
def __call__(self):
if self.action is None:
return
+
for action, desc, func in actions:
if action == self.action:
return func(self, self.args)
@@ -676,6 +678,12 @@ def main(args=None):
if dispatcher.action is None:
return
return dispatcher()
+ except KeyboardInterrupt:
+ logger.info('interrupted')
+ return 1
+ except (IOError, os.error, PackagingError, CCompilerError) as exc:
+ logger.exception(exc)
+ return 1
finally:
logger.setLevel(old_level)
logger.handlers[:] = old_handlers
diff --git a/Lib/packaging/tests/test_database.py b/Lib/packaging/tests/test_database.py
index 3eeda83570..119fa23624 100644
--- a/Lib/packaging/tests/test_database.py
+++ b/Lib/packaging/tests/test_database.py
@@ -302,7 +302,7 @@ class TestDatabase(support.LoggingCatcher,
self.assertIsInstance(dist, Distribution)
if (dist.name in dict(fake_dists) and
dist.path.startswith(self.fake_dists_path)):
- found_dists.append((dist.name, dist.metadata['version'], ))
+ found_dists.append((dist.name, dist.version))
else:
# check that it doesn't find anything more than this
self.assertFalse(dist.path.startswith(self.fake_dists_path))
@@ -323,7 +323,7 @@ class TestDatabase(support.LoggingCatcher,
self.assertIsInstance(dist, (Distribution, EggInfoDistribution))
if (dist.name in dict(fake_dists) and
dist.path.startswith(self.fake_dists_path)):
- found_dists.append((dist.name, dist.metadata['version']))
+ found_dists.append((dist.name, dist.version))
else:
self.assertFalse(dist.path.startswith(self.fake_dists_path))
@@ -489,17 +489,17 @@ class TestDatabase(support.LoggingCatcher,
checkLists([], _yield_distributions(False, False, sys.path))
- found = [(dist.name, dist.metadata['Version'])
+ found = [(dist.name, dist.version)
for dist in _yield_distributions(False, True, sys.path)
if dist.path.startswith(self.fake_dists_path)]
checkLists(eggs, found)
- found = [(dist.name, dist.metadata['Version'])
+ found = [(dist.name, dist.version)
for dist in _yield_distributions(True, False, sys.path)
if dist.path.startswith(self.fake_dists_path)]
checkLists(dists, found)
- found = [(dist.name, dist.metadata['Version'])
+ found = [(dist.name, dist.version)
for dist in _yield_distributions(True, True, sys.path)
if dist.path.startswith(self.fake_dists_path)]
checkLists(dists + eggs, found)
diff --git a/Lib/packaging/tests/test_install.py b/Lib/packaging/tests/test_install.py
index 35733c8bf5..cf0817ca4d 100644
--- a/Lib/packaging/tests/test_install.py
+++ b/Lib/packaging/tests/test_install.py
@@ -29,7 +29,7 @@ class InstalledDist:
self.metadata['Requires-Dist'] = deps
def __repr__(self):
- return '<InstalledDist %s>' % self.metadata['Name']
+ return '<InstalledDist %r>' % self.metadata['Name']
class ToInstallDist:
diff --git a/Lib/pipes.py b/Lib/pipes.py
index 51666a8ae7..693309fff0 100644
--- a/Lib/pipes.py
+++ b/Lib/pipes.py
@@ -62,7 +62,9 @@ For an example, see the function test() at the end of the file.
import re
import os
import tempfile
-import string
+# we import the quote function rather than the module for backward compat
+# (quote used to be an undocumented but used function in pipes)
+from shlex import quote
__all__ = ["Template"]
@@ -245,22 +247,3 @@ def makepipeline(infile, steps, outfile):
cmdlist = trapcmd + '\n' + cmdlist + '\n' + rmcmd
#
return cmdlist
-
-
-# Reliably quote a string as a single argument for /bin/sh
-
-# Safe unquoted
-_safechars = frozenset(string.ascii_letters + string.digits + '@%_-+=:,./')
-
-def quote(file):
- """Return a shell-escaped version of the file string."""
- for c in file:
- if c not in _safechars:
- break
- else:
- if not file:
- return "''"
- return file
- # use single quotes, and put single quotes into double quotes
- # the string $'b is then quoted as '$'"'"'b'
- return "'" + file.replace("'", "'\"'\"'") + "'"
diff --git a/Lib/pstats.py b/Lib/pstats.py
index 8a025cdc54..3f0add2c65 100644
--- a/Lib/pstats.py
+++ b/Lib/pstats.py
@@ -1,13 +1,9 @@
"""Class for printing reports on profiled python code."""
-# Class for printing reports on profiled python code. rev 1.0 4/1/94
-#
# Written by James Roskind
# Based on prior profile module by Sjoerd Mullender...
# which was hacked somewhat by: Guido van Rossum
-"""Class for profiling Python code."""
-
# Copyright Disney Enterprises, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement
#
diff --git a/Lib/shlex.py b/Lib/shlex.py
index 3edd3db1ed..279ab48405 100644
--- a/Lib/shlex.py
+++ b/Lib/shlex.py
@@ -6,13 +6,14 @@
# Posix compliance, split(), string arguments, and
# iterator interface by Gustavo Niemeyer, April 2003.
-import os.path
+import os
+import re
import sys
from collections import deque
from io import StringIO
-__all__ = ["shlex", "split"]
+__all__ = ["shlex", "split", "quote"]
class shlex:
"A lexical analyzer class for simple shell-like syntaxes."
@@ -274,6 +275,21 @@ def split(s, comments=False, posix=True):
lex.commenters = ''
return list(lex)
+
+_find_unsafe = re.compile(r'[^\w\d@%_\-\+=:,\./]').search
+
+def quote(s):
+ """Return a shell-escaped version of the string *s*."""
+ if not s:
+ return "''"
+ if _find_unsafe(s) is None:
+ return s
+
+ # use single quotes, and put single quotes into double quotes
+ # the string $'b is then quoted as '$'"'"'b'
+ return "'" + s.replace("'", "'\"'\"'") + "'"
+
+
if __name__ == '__main__':
if len(sys.argv) == 1:
lexer = shlex()
diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py
index 0c656fd098..42e118ba8f 100644
--- a/Lib/test/list_tests.py
+++ b/Lib/test/list_tests.py
@@ -4,17 +4,10 @@ Tests common to list and UserList.UserList
import sys
import os
+from functools import cmp_to_key
from test import support, seq_tests
-def CmpToKey(mycmp):
- 'Convert a cmp= function into a key= function'
- class K(object):
- def __init__(self, obj):
- self.obj = obj
- def __lt__(self, other):
- return mycmp(self.obj, other.obj) == -1
- return K
class CommonTest(seq_tests.CommonTest):
@@ -484,7 +477,7 @@ class CommonTest(seq_tests.CommonTest):
return 1
else: # a > b
return -1
- u.sort(key=CmpToKey(revcmp))
+ u.sort(key=cmp_to_key(revcmp))
self.assertEqual(u, self.type2test([2,1,0,-1,-2]))
# The following dumps core in unpatched Python 1.5:
@@ -497,7 +490,7 @@ class CommonTest(seq_tests.CommonTest):
else: # xmod > ymod
return 1
z = self.type2test(range(12))
- z.sort(key=CmpToKey(myComparison))
+ z.sort(key=cmp_to_key(myComparison))
self.assertRaises(TypeError, z.sort, 2)
@@ -509,7 +502,8 @@ class CommonTest(seq_tests.CommonTest):
return -1
else: # x > y
return 1
- self.assertRaises(ValueError, z.sort, key=CmpToKey(selfmodifyingComparison))
+ self.assertRaises(ValueError, z.sort,
+ key=cmp_to_key(selfmodifyingComparison))
self.assertRaises(TypeError, z.sort, 42, 42, 42, 42)
diff --git a/Lib/test/test_modulefinder.py b/Lib/test/test_modulefinder.py
index a1842178df..c5fc320f64 100644
--- a/Lib/test/test_modulefinder.py
+++ b/Lib/test/test_modulefinder.py
@@ -1,7 +1,7 @@
-import __future__
import os
+import errno
+import shutil
import unittest
-import distutils.dir_util
import tempfile
from test import support
@@ -9,7 +9,7 @@ from test import support
import modulefinder
TEST_DIR = tempfile.mkdtemp()
-TEST_PATH = [TEST_DIR, os.path.dirname(__future__.__file__)]
+TEST_PATH = [TEST_DIR, os.path.dirname(tempfile.__file__)]
# Each test description is a list of 5 items:
#
@@ -196,12 +196,17 @@ a/module.py
from . import bar
"""]
+
def open_file(path):
- ##print "#", os.path.abspath(path)
dirname = os.path.dirname(path)
- distutils.dir_util.mkpath(dirname)
+ try:
+ os.makedirs(dirname)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
return open(path, "w")
+
def create_package(source):
ofi = None
try:
@@ -216,6 +221,7 @@ def create_package(source):
if ofi:
ofi.close()
+
class ModuleFinderTest(unittest.TestCase):
def _do_test(self, info, report=False):
import_this, modules, missing, maybe_missing, source = info
@@ -234,19 +240,17 @@ class ModuleFinderTest(unittest.TestCase):
## import traceback; traceback.print_exc()
## sys.path = opath
## return
- modules = set(modules)
- found = set(mf.modules.keys())
- more = list(found - modules)
- less = list(modules - found)
+ modules = sorted(set(modules))
+ found = sorted(mf.modules)
# check if we found what we expected, not more, not less
- self.assertEqual((more, less), ([], []))
+ self.assertEqual(found, modules)
# check for missing and maybe missing modules
bad, maybe = mf.any_missing_maybe()
self.assertEqual(bad, missing)
self.assertEqual(maybe, maybe_missing)
finally:
- distutils.dir_util.remove_tree(TEST_DIR)
+ shutil.rmtree(TEST_DIR)
def test_package(self):
self._do_test(package_test)
@@ -254,25 +258,23 @@ class ModuleFinderTest(unittest.TestCase):
def test_maybe(self):
self._do_test(maybe_test)
- if getattr(__future__, "absolute_import", None):
+ def test_maybe_new(self):
+ self._do_test(maybe_test_new)
- def test_maybe_new(self):
- self._do_test(maybe_test_new)
+ def test_absolute_imports(self):
+ self._do_test(absolute_import_test)
- def test_absolute_imports(self):
- self._do_test(absolute_import_test)
+ def test_relative_imports(self):
+ self._do_test(relative_import_test)
- def test_relative_imports(self):
- self._do_test(relative_import_test)
+ def test_relative_imports_2(self):
+ self._do_test(relative_import_test_2)
- def test_relative_imports_2(self):
- self._do_test(relative_import_test_2)
+ def test_relative_imports_3(self):
+ self._do_test(relative_import_test_3)
- def test_relative_imports_3(self):
- self._do_test(relative_import_test_3)
def test_main():
- distutils.log.set_threshold(distutils.log.WARN)
support.run_unittest(ModuleFinderTest)
if __name__ == "__main__":
diff --git a/Lib/test/test_pipes.py b/Lib/test/test_pipes.py
index f2b58d5e3d..6a7b45fb46 100644
--- a/Lib/test/test_pipes.py
+++ b/Lib/test/test_pipes.py
@@ -79,20 +79,6 @@ class SimplePipeTests(unittest.TestCase):
with open(TESTFN) as f:
self.assertEqual(f.read(), d)
- def testQuoting(self):
- safeunquoted = string.ascii_letters + string.digits + '@%_-+=:,./'
- unsafe = '"`$\\!'
-
- self.assertEqual(pipes.quote(''), "''")
- self.assertEqual(pipes.quote(safeunquoted), safeunquoted)
- self.assertEqual(pipes.quote('test file name'), "'test file name'")
- for u in unsafe:
- self.assertEqual(pipes.quote('test%sname' % u),
- "'test%sname'" % u)
- for u in unsafe:
- self.assertEqual(pipes.quote("test%s'name'" % u),
- "'test%s'\"'\"'name'\"'\"''" % u)
-
def testRepr(self):
t = pipes.Template()
self.assertEqual(repr(t), "<Template instance, steps=[]>")
diff --git a/Lib/test/test_shlex.py b/Lib/test/test_shlex.py
index 25e4b6df6c..ea3d777ceb 100644
--- a/Lib/test/test_shlex.py
+++ b/Lib/test/test_shlex.py
@@ -1,6 +1,7 @@
-import unittest
-import os, sys, io
+import io
import shlex
+import string
+import unittest
from test import support
@@ -173,6 +174,21 @@ class ShlexTest(unittest.TestCase):
"%s: %s != %s" %
(self.data[i][0], l, self.data[i][1:]))
+ def testQuote(self):
+ safeunquoted = string.ascii_letters + string.digits + '@%_-+=:,./'
+ unsafe = '"`$\\!'
+
+ self.assertEqual(shlex.quote(''), "''")
+ self.assertEqual(shlex.quote(safeunquoted), safeunquoted)
+ self.assertEqual(shlex.quote('test file name'), "'test file name'")
+ for u in unsafe:
+ self.assertEqual(shlex.quote('test%sname' % u),
+ "'test%sname'" % u)
+ for u in unsafe:
+ self.assertEqual(shlex.quote("test%s'name'" % u),
+ "'test%s'\"'\"'name'\"'\"''" % u)
+
+
# Allow this test to be used with old shlex.py
if not getattr(shlex, "split", None):
for methname in dir(ShlexTest):
diff --git a/Lib/test/test_sort.py b/Lib/test/test_sort.py
index 55503b57a8..8f6af64470 100644
--- a/Lib/test/test_sort.py
+++ b/Lib/test/test_sort.py
@@ -2,18 +2,11 @@ from test import support
import random
import sys
import unittest
+from functools import cmp_to_key
verbose = support.verbose
nerrors = 0
-def CmpToKey(mycmp):
- 'Convert a cmp= function into a key= function'
- class K(object):
- def __init__(self, obj):
- self.obj = obj
- def __lt__(self, other):
- return mycmp(self.obj, other.obj) == -1
- return K
def check(tag, expected, raw, compare=None):
global nerrors
@@ -23,7 +16,7 @@ def check(tag, expected, raw, compare=None):
orig = raw[:] # save input in case of error
if compare:
- raw.sort(key=CmpToKey(compare))
+ raw.sort(key=cmp_to_key(compare))
else:
raw.sort()
@@ -108,7 +101,7 @@ class TestBase(unittest.TestCase):
print(" Checking against an insane comparison function.")
print(" If the implementation isn't careful, this may segfault.")
s = x[:]
- s.sort(key=CmpToKey(lambda a, b: int(random.random() * 3) - 1))
+ s.sort(key=cmp_to_key(lambda a, b: int(random.random() * 3) - 1))
check("an insane function left some permutation", x, s)
if len(x) >= 2:
@@ -165,12 +158,12 @@ class TestBugs(unittest.TestCase):
L.pop()
return (x > y) - (x < y)
L = [1,2]
- self.assertRaises(ValueError, L.sort, key=CmpToKey(mutating_cmp))
+ self.assertRaises(ValueError, L.sort, key=cmp_to_key(mutating_cmp))
def mutating_cmp(x, y):
L.append(3)
del L[:]
return (x > y) - (x < y)
- self.assertRaises(ValueError, L.sort, key=CmpToKey(mutating_cmp))
+ self.assertRaises(ValueError, L.sort, key=cmp_to_key(mutating_cmp))
memorywaster = [memorywaster]
#==============================================================================
@@ -185,7 +178,7 @@ class TestDecorateSortUndecorate(unittest.TestCase):
def my_cmp(x, y):
xlower, ylower = x.lower(), y.lower()
return (xlower > ylower) - (xlower < ylower)
- copy.sort(key=CmpToKey(my_cmp))
+ copy.sort(key=cmp_to_key(my_cmp))
def test_baddecorator(self):
data = 'The quick Brown fox Jumped over The lazy Dog'.split()
@@ -261,8 +254,8 @@ class TestDecorateSortUndecorate(unittest.TestCase):
def my_cmp_reversed(x, y):
x0, y0 = x[0], y[0]
return (y0 > x0) - (y0 < x0)
- data.sort(key=CmpToKey(my_cmp), reverse=True)
- copy1.sort(key=CmpToKey(my_cmp_reversed))
+ data.sort(key=cmp_to_key(my_cmp), reverse=True)
+ copy1.sort(key=cmp_to_key(my_cmp_reversed))
self.assertEqual(data, copy1)
copy2.sort(key=lambda x: x[0], reverse=True)
self.assertEqual(data, copy2)
diff --git a/Lib/threading.py b/Lib/threading.py
index 9681f02fb1..222e5d992a 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -172,10 +172,7 @@ class _RLock(_Verbose):
_PyRLock = _RLock
-def Condition(*args, **kwargs):
- return _Condition(*args, **kwargs)
-
-class _Condition(_Verbose):
+class Condition(_Verbose):
def __init__(self, lock=None, verbose=None):
_Verbose.__init__(self, verbose)
@@ -308,10 +305,7 @@ class _Condition(_Verbose):
notifyAll = notify_all
-def Semaphore(*args, **kwargs):
- return _Semaphore(*args, **kwargs)
-
-class _Semaphore(_Verbose):
+class Semaphore(_Verbose):
# After Tim Peters' semaphore class, but not quite the same (no maximum)
@@ -366,25 +360,19 @@ class _Semaphore(_Verbose):
self.release()
-def BoundedSemaphore(*args, **kwargs):
- return _BoundedSemaphore(*args, **kwargs)
-
-class _BoundedSemaphore(_Semaphore):
+class BoundedSemaphore(Semaphore):
"""Semaphore that checks that # releases is <= # acquires"""
def __init__(self, value=1, verbose=None):
- _Semaphore.__init__(self, value, verbose)
+ Semaphore.__init__(self, value, verbose)
self._initial_value = value
def release(self):
if self._value >= self._initial_value:
raise ValueError("Semaphore released too many times")
- return _Semaphore.release(self)
+ return Semaphore.release(self)
-def Event(*args, **kwargs):
- return _Event(*args, **kwargs)
-
-class _Event(_Verbose):
+class Event(_Verbose):
# After Tim Peters' event class (without is_posted())
@@ -918,10 +906,7 @@ class Thread(_Verbose):
# The timer class was contributed by Itamar Shtull-Trauring
-def Timer(*args, **kwargs):
- return _Timer(*args, **kwargs)
-
-class _Timer(Thread):
+class Timer(Thread):
"""Call a function after a specified number of seconds:
t = Timer(30.0, f, args=[], kwargs={})
diff --git a/Misc/NEWS b/Misc/NEWS
index 6ba892c450..d90faf9d7a 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -244,6 +244,16 @@ Core and Builtins
Library
-------
+- Issue #10968: Remove indirection in threading. The public names (Thread,
+ Condition, etc.) used to be factory functions returning instances of hidden
+ classes (_Thread, _Condition, etc.), because (if Guido recalls correctly) this
+ code pre-dates the ability to subclass extension types. It is now possible to
+ inherit from Thread and other classes, without having to import the private
+ underscored names like multiprocessing did.
+
+- Issue #9723: Add shlex.quote functions, to escape filenames and command
+ lines.
+
- Issue #12603: Fix pydoc.synopsis() on files with non-negative st_mtime.
- Issue #12514: Use try/finally to assure the timeit module restores garbage
diff --git a/Python/marshal.c b/Python/marshal.c
index 35fcd3afb3..edf0366c9a 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -57,7 +57,7 @@ typedef struct {
int error; /* see WFERR_* values */
int depth;
/* If fp == NULL, the following are valid: */
- PyObject * readable; /* Stream-like object being read from */
+ PyObject *readable; /* Stream-like object being read from */
PyObject *str;
PyObject *current_filename;
char *ptr;
@@ -467,7 +467,7 @@ typedef WFILE RFILE; /* Same struct with different invariants */
static int
r_string(char *s, int n, RFILE *p)
{
- char * ptr;
+ char *ptr;
int read, left;
if (!p->readable) {
@@ -566,7 +566,7 @@ r_long(RFILE *p)
static PyObject *
r_long64(RFILE *p)
{
- PyObject * result = NULL;
+ PyObject *result = NULL;
long lo4 = r_long(p);
long hi4 = r_long(p);
diff --git a/Tools/scripts/abitype.py b/Tools/scripts/abitype.py
index e35ef6a1d3..4d96c8b70e 100644..100755
--- a/Tools/scripts/abitype.py
+++ b/Tools/scripts/abitype.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
# This script converts a C file to use the PEP 384 type definition API
# Usage: abitype.py < old_code > new_code
import re, sys
diff --git a/Tools/scripts/cleanfuture.py b/Tools/scripts/cleanfuture.py
index b48ab60dd6..b48ab60dd6 100644..100755
--- a/Tools/scripts/cleanfuture.py
+++ b/Tools/scripts/cleanfuture.py
diff --git a/Tools/scripts/combinerefs.py b/Tools/scripts/combinerefs.py
index e10e49ad7c..e10e49ad7c 100644..100755
--- a/Tools/scripts/combinerefs.py
+++ b/Tools/scripts/combinerefs.py
diff --git a/Tools/scripts/db2pickle.py b/Tools/scripts/db2pickle.py
index a5532a8f3a..a5532a8f3a 100644..100755
--- a/Tools/scripts/db2pickle.py
+++ b/Tools/scripts/db2pickle.py
diff --git a/Tools/scripts/diff.py b/Tools/scripts/diff.py
index 52dcab1ff9..9efb078fb8 100644..100755
--- a/Tools/scripts/diff.py
+++ b/Tools/scripts/diff.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
""" Command line interface to difflib.py providing diffs in four formats:
* ndiff: lists every line and highlights interline changes.
diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py
index 443f052c4e..443f052c4e 100644..100755
--- a/Tools/scripts/find_recursionlimit.py
+++ b/Tools/scripts/find_recursionlimit.py
diff --git a/Tools/scripts/get-remote-certificate.py b/Tools/scripts/get-remote-certificate.py
index 5811f202ed..5811f202ed 100644..100755
--- a/Tools/scripts/get-remote-certificate.py
+++ b/Tools/scripts/get-remote-certificate.py
diff --git a/Tools/scripts/mailerdaemon.py b/Tools/scripts/mailerdaemon.py
index 4934b92eaa..aeb451e942 100644..100755
--- a/Tools/scripts/mailerdaemon.py
+++ b/Tools/scripts/mailerdaemon.py
@@ -1,4 +1,5 @@
-"""mailerdaemon - classes to parse mailer-daemon messages"""
+#!/usr/bin/env python3
+"""Classes to parse mailer-daemon messages."""
import calendar
import email.message
@@ -6,7 +7,10 @@ import re
import os
import sys
-Unparseable = 'mailerdaemon.Unparseable'
+
+class Unparseable(Exception):
+ pass
+
class ErrorMessage(email.message.Message):
def __init__(self):
@@ -18,8 +22,10 @@ class ErrorMessage(email.message.Message):
if not sub:
return 0
sub = sub.lower()
- if sub.startswith('waiting mail'): return 1
- if 'warning' in sub: return 1
+ if sub.startswith('waiting mail'):
+ return 1
+ if 'warning' in sub:
+ return 1
self.sub = sub
return 0
@@ -145,14 +151,17 @@ def emparse_list(fp, sub):
errors.append(' '.join((email.strip()+': '+reason).split()))
return errors
-EMPARSERS = [emparse_list, ]
+EMPARSERS = [emparse_list]
def sort_numeric(a, b):
a = int(a)
b = int(b)
- if a < b: return -1
- elif a > b: return 1
- else: return 0
+ if a < b:
+ return -1
+ elif a > b:
+ return 1
+ else:
+ return 0
def parsedir(dir, modify):
os.chdir(dir)
diff --git a/Tools/scripts/make_ctype.py b/Tools/scripts/make_ctype.py
index 359d6b3160..afee1c5833 100644..100755
--- a/Tools/scripts/make_ctype.py
+++ b/Tools/scripts/make_ctype.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
"""Script that generates the ctype.h-replacement in stringobject.c."""
NAMES = ("LOWER", "UPPER", "ALPHA", "DIGIT", "XDIGIT", "ALNUM", "SPACE")
diff --git a/Tools/scripts/md5sum.py b/Tools/scripts/md5sum.py
index 743da72aa8..743da72aa8 100644..100755
--- a/Tools/scripts/md5sum.py
+++ b/Tools/scripts/md5sum.py
diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py
index d42bc8a4bf..8b0d3cdb1e 100644..100755
--- a/Tools/scripts/patchcheck.py
+++ b/Tools/scripts/patchcheck.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
import re
import sys
import shutil
diff --git a/Tools/scripts/pickle2db.py b/Tools/scripts/pickle2db.py
index b5b6571863..b5b6571863 100644..100755
--- a/Tools/scripts/pickle2db.py
+++ b/Tools/scripts/pickle2db.py
diff --git a/Tools/scripts/pysource.py b/Tools/scripts/pysource.py
index c7dbe605d4..c7dbe605d4 100644..100755
--- a/Tools/scripts/pysource.py
+++ b/Tools/scripts/pysource.py
diff --git a/Tools/scripts/reindent-rst.py b/Tools/scripts/reindent-rst.py
index ceb84bfd3c..25608af66a 100755
--- a/Tools/scripts/reindent-rst.py
+++ b/Tools/scripts/reindent-rst.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Make a reST file compliant to our pre-commit hook.
# Currently just remove trailing whitespace.
diff --git a/Tools/scripts/svneol.py b/Tools/scripts/svneol.py
index 8abdd01529..8abdd01529 100644..100755
--- a/Tools/scripts/svneol.py
+++ b/Tools/scripts/svneol.py