Branch merge

This commit is contained in:
Éric Araujo 2011-07-29 14:30:03 +02:00
commit 0bbacc621c
52 changed files with 256 additions and 294 deletions

View file

@ -14,6 +14,7 @@ platform
pybuilddir.txt pybuilddir.txt
pyconfig.h pyconfig.h
libpython*.a libpython*.a
libpython*.so*
python.exe python.exe
python-gdb.py python-gdb.py
reflog.txt reflog.txt

1
.gitignore vendored
View file

@ -37,6 +37,7 @@ build/
config.log config.log
config.status config.status
libpython*.a libpython*.a
libpython*.so*
pybuilddir.txt pybuilddir.txt
pyconfig.h pyconfig.h
python python

View file

@ -41,14 +41,13 @@ PCbuild/amd64/
syntax: glob syntax: glob
libpython*.a libpython*.a
libpython*.so*
*.swp *.swp
*.o *.o
*.pyc *.pyc
*.pyo *.pyo
*.pyd *.pyd
*.cover *.cover
*.orig
*.rej
*~ *~
Lib/lib2to3/*.pickle Lib/lib2to3/*.pickle
Lib/test/data/* Lib/test/data/*

View file

@ -203,6 +203,7 @@ docs@python.org), and we'll be glad to correct the problem.
* Kalle Svensson * Kalle Svensson
* Jim Tittsler * Jim Tittsler
* David Turner * David Turner
* Sandro Tosi
* Ville Vainio * Ville Vainio
* Nadeem Vawda * Nadeem Vawda
* Martijn Vries * Martijn Vries

View file

@ -72,8 +72,8 @@ setup script). Indirectly provides the :class:`distutils.dist.Distribution` and
| | be built | :class:`distutils.core.Extension` | | | be built | :class:`distutils.core.Extension` |
+--------------------+--------------------------------+-------------------------------------------------------------+ +--------------------+--------------------------------+-------------------------------------------------------------+
| *classifiers* | A list of categories for the | The list of available | | *classifiers* | A list of categories for the | The list of available |
| | package | categorizations is at | | | package | categorizations is available on `PyPI |
| | | http://pypi.python.org/pypi?:action=list_classifiers. | | | | <http://pypi.python.org/pypi?:action=list_classifiers>`_. |
+--------------------+--------------------------------+-------------------------------------------------------------+ +--------------------+--------------------------------+-------------------------------------------------------------+
| *distclass* | the :class:`Distribution` | A subclass of | | *distclass* | the :class:`Distribution` | A subclass of |
| | class to use | :class:`distutils.core.Distribution` | | | class to use | :class:`distutils.core.Distribution` |

View file

@ -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 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 --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 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 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 module distribution that doesn't have an easy-to-use installer for your

View file

@ -431,7 +431,8 @@ Glossary
mapping mapping
A container object that supports arbitrary key lookups and implements the 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 :ref:`abstract base classes <collections-abstract-base-classes>`. Examples
include :class:`dict`, :class:`collections.defaultdict`, include :class:`dict`, :class:`collections.defaultdict`,
:class:`collections.OrderedDict` and :class:`collections.Counter`. :class:`collections.OrderedDict` and :class:`collections.Counter`.

View file

@ -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 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 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 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 Sounds like things are also complicated for other BSDs. In response
to my python-dev query, Thomas Wouters said: to my python-dev query, Thomas Wouters said:

View file

@ -67,8 +67,8 @@ module distribution being built/packaged/distributed/installed.
| | be built | :class:`packaging.compiler.extension.Extension` | | | be built | :class:`packaging.compiler.extension.Extension` |
+--------------------+--------------------------------+-------------------------------------------------------------+ +--------------------+--------------------------------+-------------------------------------------------------------+
| *classifiers* | A list of categories for the | The list of available | | *classifiers* | A list of categories for the | The list of available |
| | distribution | categorizations is at | | | distribution | categorizations is available on `PyPI |
| | | http://pypi.python.org/pypi?:action=list_classifiers. | | | | <http://pypi.python.org/pypi?:action=list_classifiers>`_. |
+--------------------+--------------------------------+-------------------------------------------------------------+ +--------------------+--------------------------------+-------------------------------------------------------------+
| *distclass* | the :class:`Distribution` | A subclass of | | *distclass* | the :class:`Distribution` | A subclass of |
| | class to use | :class:`packaging.dist.Distribution` | | | class to use | :class:`packaging.dist.Distribution` |

View file

@ -39,7 +39,7 @@ The Python standard library provides two different profilers:
2. :mod:`profile`, a pure Python module whose interface is imitated by 2. :mod:`profile`, a pure Python module whose interface is imitated by
:mod:`cProfile`. Adds significant overhead to profiled programs. If you're :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 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 The :mod:`profile` and :mod:`cProfile` modules export the same interface, so
they are mostly interchangeable; :mod:`cProfile` has a much lower overhead but 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 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 best results with a custom timer, it might be necessary to hard-code it in the C
source of the internal :mod:`_lsprof` module. 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.

View file

@ -34,6 +34,22 @@ The :mod:`shlex` module defines the following functions:
passing ``None`` for *s* will read the string to split from standard passing ``None`` for *s* will read the string to split from standard
input. 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: The :mod:`shlex` module defines the following class:
@ -282,5 +298,4 @@ parsing rules.
* EOF is signaled with a :const:`None` value; * EOF is signaled with a :const:`None` value;
* Quoted empty strings (``''``) are allowed; * Quoted empty strings (``''``) are allowed.

View file

@ -159,12 +159,18 @@ Directory and files operations
.. function:: move(src, dst) .. 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 If the destination is a directory or a symlink to a directory, then *src* is
when *src* and *dst* are on different filesystems or in case of windows where moved inside that directory.
rename is not supported when *dst* exists, fallback to copying *src* (with
:func:`copy2`) to the *dst* and then remove *src*. 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) .. function:: disk_usage(path)
@ -177,9 +183,9 @@ Directory and files operations
.. exception:: Error .. exception:: Error
This exception collects exceptions that raised during a multi-file operation. For This exception collects exceptions that are raised during a multi-file
:func:`copytree`, the exception argument is a list of 3-tuples (*srcname*, operation. For :func:`copytree`, the exception argument is a list of 3-tuples
*dstname*, *exception*). (*srcname*, *dstname*, *exception*).
.. _shutil-example: .. _shutil-example:
@ -277,7 +283,7 @@ Archiving operations
.. function:: get_archive_formats() .. 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)`` Each element of the returned sequence is a tuple ``(name, description)``
By default :mod:`shutil` provides these formats: By default :mod:`shutil` provides these formats:
@ -295,7 +301,7 @@ Archiving operations
.. function:: register_archive_format(name, function, [extra_args, [description]]) .. 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. will be used to invoke the archiver.
If given, *extra_args* is a sequence of ``(name, value)`` pairs that will be If given, *extra_args* is a sequence of ``(name, value)`` pairs that will be

View file

@ -92,7 +92,8 @@ This module defines one class called :class:`Popen`:
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly... >>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...
*shell=False* does not suffer from this vulnerability; the above Note may be *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 On Windows: the :class:`Popen` class uses CreateProcess() to execute the
child program, which operates on strings. If *args* is a sequence, it will child program, which operates on strings. If *args* is a sequence, it will
@ -871,3 +872,7 @@ runtime):
described in rule 3. described in rule 3.
.. seealso::
:mod:`shlex`
Module which provides function to parse and escape command lines.

View file

@ -494,36 +494,6 @@ The :mod:`http.cookies` module contains the following notice::
PERFORMANCE OF THIS SOFTWARE. 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 Execution tracing
----------------- -----------------

View file

@ -5,7 +5,6 @@ c-api/sequence,,:i2,o[i1:i2]
c-api/sequence,,:i2,o[i1:i2] = v c-api/sequence,,:i2,o[i1:i2] = v
c-api/sequence,,:i2,del o[i1:i2] c-api/sequence,,:i2,del o[i1:i2]
c-api/unicode,,:end,str[start:end] c-api/unicode,,:end,str[start:end]
distutils/apiref,,:action,http://pypi.python.org/pypi?:action=list_classifiers
distutils/setupscript,,::, distutils/setupscript,,::,
extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))" extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))"
extending/extending,,:set,"if (PyArg_ParseTuple(args, ""O:set_callback"", &temp)) {" 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,::,"'Programming Language :: Python :: 2.7',"
library/pprint,209,::,"'Topic :: Software Development :: Libraries'," library/pprint,209,::,"'Topic :: Software Development :: Libraries',"
library/pprint,209,::,"'Topic :: Software Development :: Libraries :: Python Modules']," 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/examples,,`,This is the description of the ``foobar`` project.
packaging/setupcfg,,::,Development Status :: 3 - Alpha packaging/setupcfg,,::,Development Status :: 3 - Alpha
packaging/setupcfg,,::,License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) packaging/setupcfg,,::,License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)

1 c-api/arg :ref PyArg_ParseTuple(args, "O|O:ref", &object, &callback)
5 c-api/sequence :i2 o[i1:i2] = v
6 c-api/sequence :i2 del o[i1:i2]
7 c-api/unicode :end str[start:end]
distutils/apiref :action http://pypi.python.org/pypi?:action=list_classifiers
8 distutils/setupscript ::
9 extending/embedding :numargs if(!PyArg_ParseTuple(args, ":numargs"))
10 extending/extending :set if (PyArg_ParseTuple(args, "O:set_callback", &temp)) {
494 library/pprint 209 :: 'Programming Language :: Python :: 2.7',
495 library/pprint 209 :: 'Topic :: Software Development :: Libraries',
496 library/pprint 209 :: 'Topic :: Software Development :: Libraries :: Python Modules'],
library/packaging.dist :action http://pypi.python.org/pypi?:action=list_classifiers
497 packaging/examples ` This is the description of the ``foobar`` project.
498 packaging/setupcfg :: Development Status :: 3 - Alpha
499 packaging/setupcfg :: License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)

View file

@ -598,24 +598,24 @@ occurs within the definition of a class.
Name mangling is helpful for letting subclasses override methods without Name mangling is helpful for letting subclasses override methods without
breaking intraclass method calls. For example:: breaking intraclass method calls. For example::
class Mapping: class Mapping:
def __init__(self, iterable): def __init__(self, iterable):
self.items_list = [] self.items_list = []
self.__update(iterable) self.__update(iterable)
def update(self, iterable): def update(self, iterable):
for item in iterable: for item in iterable:
self.items_list.append(item) 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): def update(self, keys, values):
# provides new signature for update() # provides new signature for update()
# but does not break __init__() # but does not break __init__()
for item in zip(keys, values): for item in zip(keys, values):
self.items_list.append(item) self.items_list.append(item)
Note that the mangling rules are designed mostly to avoid accidents; it still is 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 possible to access or modify a variable that is considered private. This can

View file

@ -94,8 +94,8 @@ versions.
curses curses
------ ------
The :class:`curses.window` class has a new :class:`~curses.window.get_wch` The :class:`curses.window` class has a new :meth:`~curses.window.get_wch` method
method to a wide character. Patch by Iñigo Serna. to get a wide character. Patch by Iñigo Serna.
(:issue:`6755`) (:issue:`6755`)

View file

@ -1,6 +1,5 @@
"""Find modules used by a script, using introspection.""" """Find modules used by a script, using introspection."""
from __future__ import generators
import dis import dis
import imp import imp
import marshal import marshal
@ -9,8 +8,6 @@ import sys
import types import types
import struct import struct
READ_MODE = "rU"
# XXX Clean up once str8's cstor matches bytes. # XXX Clean up once str8's cstor matches bytes.
LOAD_CONST = bytes([dis.opname.index('LOAD_CONST')]) LOAD_CONST = bytes([dis.opname.index('LOAD_CONST')])
IMPORT_NAME = bytes([dis.opname.index('IMPORT_NAME')]) IMPORT_NAME = bytes([dis.opname.index('IMPORT_NAME')])
@ -29,8 +26,7 @@ packagePathMap = {}
# A Public interface # A Public interface
def AddPackagePath(packagename, path): def AddPackagePath(packagename, path):
paths = packagePathMap.get(packagename, []) paths = packagePathMap.setdefault(packagename, []).append(path)
paths.append(path)
packagePathMap[packagename] = paths packagePathMap[packagename] = paths
replacePackageMap = {} replacePackageMap = {}
@ -106,14 +102,14 @@ class ModuleFinder:
def run_script(self, pathname): def run_script(self, pathname):
self.msg(2, "run_script", pathname) self.msg(2, "run_script", pathname)
with open(pathname, READ_MODE) as fp: with open(pathname) as fp:
stuff = ("", "r", imp.PY_SOURCE) stuff = ("", "r", imp.PY_SOURCE)
self.load_module('__main__', fp, pathname, stuff) self.load_module('__main__', fp, pathname, stuff)
def load_file(self, pathname): def load_file(self, pathname):
dir, name = os.path.split(pathname) dir, name = os.path.split(pathname)
name, ext = os.path.splitext(name) name, ext = os.path.splitext(name)
with open(pathname, READ_MODE) as fp: with open(pathname) as fp:
stuff = (ext, "r", imp.PY_SOURCE) stuff = (ext, "r", imp.PY_SOURCE)
self.load_module(name, fp, pathname, stuff) self.load_module(name, fp, pathname, stuff)
@ -270,7 +266,8 @@ class ModuleFinder:
try: try:
m = self.load_module(fqname, fp, pathname, stuff) m = self.load_module(fqname, fp, pathname, stuff)
finally: finally:
if fp: fp.close() if fp:
fp.close()
if parent: if parent:
setattr(parent, partname, m) setattr(parent, partname, m)
self.msgout(3, "import_module ->", m) self.msgout(3, "import_module ->", m)
@ -662,4 +659,4 @@ if __name__ == '__main__':
try: try:
mf = test() mf = test()
except KeyboardInterrupt: except KeyboardInterrupt:
print("\n[interrupt]") print("\n[interrupted]")

View file

@ -51,7 +51,7 @@ import itertools
from multiprocessing import TimeoutError, cpu_count from multiprocessing import TimeoutError, cpu_count
from multiprocessing.dummy.connection import Pipe from multiprocessing.dummy.connection import Pipe
from threading import Lock, RLock, Semaphore, BoundedSemaphore from threading import Lock, RLock, Semaphore, BoundedSemaphore
from threading import Event from threading import Event, Condition
from queue import Queue 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 Process = DummyProcess
current_process = threading.current_thread current_process = threading.current_thread
current_process()._children = weakref.WeakKeyDictionary() current_process()._children = weakref.WeakKeyDictionary()

View file

@ -57,7 +57,8 @@ class Command:
from packaging.dist import Distribution from packaging.dist import Distribution
if not isinstance(dist, 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: if self.__class__ is Command:
raise RuntimeError("Command is an abstract class") raise RuntimeError("Command is an abstract class")

View file

@ -351,7 +351,7 @@ class EggInfoDistribution:
except IOError: except IOError:
requires = None requires = None
self.metadata = Metadata(path=path) self.metadata = Metadata(path=path)
self.name = self.metadata['name'] self.name = self.metadata['Name']
self.version = self.metadata['Version'] self.version = self.metadata['Version']
else: else:

View file

@ -72,7 +72,7 @@ class DependencyGraph:
self.missing[distribution].append(requirement) self.missing[distribution].append(requirement)
def _repr_dist(self, dist): 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): def repr_node(self, dist, level=1):
"""Prints only a subgraph""" """Prints only a subgraph"""
@ -145,7 +145,7 @@ def generate_graph(dists):
graph.add_distribution(dist) graph.add_distribution(dist)
provides = (dist.metadata['Provides-Dist'] + provides = (dist.metadata['Provides-Dist'] +
dist.metadata['Provides'] + dist.metadata['Provides'] +
['%s (%s)' % (dist.name, dist.metadata['Version'])]) ['%s (%s)' % (dist.name, dist.version)])
for p in provides: for p in provides:
comps = p.strip().rsplit(" ", 1) comps = p.strip().rsplit(" ", 1)

View file

@ -85,7 +85,7 @@ def _run_packaging_install(path):
dist.parse_config_files() dist.parse_config_files()
try: try:
dist.run_command('install_dist') dist.run_command('install_dist')
name = dist.metadata['name'] name = dist.metadata['Name']
return database.get_distribution(name) is not None return database.get_distribution(name) is not None
except (IOError, os.error, PackagingError, CCompilerError) as msg: except (IOError, os.error, PackagingError, CCompilerError) as msg:
raise ValueError("Failed to install, " + str(msg)) raise ValueError("Failed to install, " + str(msg))
@ -118,10 +118,10 @@ def install_local_project(path):
""" """
path = os.path.abspath(path) path = os.path.abspath(path)
if os.path.isdir(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) return _run_install_from_dir(path)
elif _is_archive_file(path): elif _is_archive_file(path):
logger.info('Installing from archive: %s', path) logger.info('Installing from archive: %r', path)
_unpacked_dir = tempfile.mkdtemp() _unpacked_dir = tempfile.mkdtemp()
try: try:
shutil.unpack_archive(path, _unpacked_dir) shutil.unpack_archive(path, _unpacked_dir)
@ -129,7 +129,7 @@ def install_local_project(path):
finally: finally:
shutil.rmtree(_unpacked_dir) shutil.rmtree(_unpacked_dir)
else: else:
logger.warning('No projects to install.') logger.warning('No project to install.')
return False return False
@ -191,7 +191,7 @@ def install_dists(dists, path, paths=None):
# reverting # reverting
for installed_dist in installed_dists: for installed_dist in installed_dists:
logger.info('Reverting %s', installed_dist) logger.info('Reverting %r', installed_dist)
remove(installed_dist.name, paths) remove(installed_dist.name, paths)
raise e raise e
return installed_dists 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(): if predicate.name.lower() != installed_project.name.lower():
continue continue
found = True found = True
logger.info('Found %s %s', installed_project.name, logger.info('Found %r %s', installed_project.name,
installed_project.metadata['version']) installed_project.version)
# if we already have something installed, check it matches the # if we already have something installed, check it matches the
# requirements # requirements
if predicate.match(installed_project.metadata['version']): if predicate.match(installed_project.version):
return infos return infos
break break
@ -336,7 +336,7 @@ def get_infos(requirements, index=None, installed=None, prefer_final=True):
try: try:
release = index.get_release(requirements) release = index.get_release(requirements)
except (ReleaseNotFound, ProjectNotFound): except (ReleaseNotFound, ProjectNotFound):
raise InstallationException('Release not found: "%s"' % requirements) raise InstallationException('Release not found: %r' % requirements)
if release is None: if release is None:
logger.info('Could not find a matching project') 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) dist = get_distribution(project_name, use_egg_info=True, paths=paths)
if dist is None: 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) files = dist.list_installed_files(local=True)
rmdirs = [] rmdirs = []
rmfiles = [] rmfiles = []
@ -423,7 +423,7 @@ def remove(project_name, paths=None, auto_confirm=True):
if not success: if not success:
logger.info('%r cannot be removed.', project_name) logger.info('%r cannot be removed.', project_name)
logger.info('Error: %s' % str(error)) logger.info('Error: %s', error)
return False return False
logger.info('Removing %r: ', project_name) logger.info('Removing %r: ', project_name)
@ -523,7 +523,7 @@ def install(project):
except InstallationConflict as e: except InstallationConflict as e:
if logger.isEnabledFor(logging.INFO): 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)) logger.info('%r conflicts with %s', project, ','.join(projects))
return True return True

View file

@ -214,7 +214,7 @@ def _create(distpatcher, args, **kw):
@action_help(generate_usage) @action_help(generate_usage)
def _generate(distpatcher, args, **kw): def _generate(distpatcher, args, **kw):
generate_setup_py() generate_setup_py()
print('The setup.py was generated') logger.info('The setup.py was generated')
@action_help(graph_usage) @action_help(graph_usage)
@ -222,7 +222,8 @@ def _graph(dispatcher, args, **kw):
name = args[1] name = args[1]
dist = get_distribution(name, use_egg_info=True) dist = get_distribution(name, use_egg_info=True)
if dist is None: if dist is None:
print('Distribution not found.') logger.warning('Distribution not found.')
return 1
else: else:
dists = get_distributions(use_egg_info=True) dists = get_distributions(use_egg_info=True)
graph = generate_graph(dists) graph = generate_graph(dists)
@ -234,8 +235,7 @@ def _install(dispatcher, args, **kw):
# first check if we are in a source directory # first check if we are in a source directory
if len(args) < 2: if len(args) < 2:
# are we inside a project dir? # are we inside a project dir?
listing = os.listdir(os.getcwd()) if os.path.isfile('setup.cfg') or os.path.isfile('setup.py'):
if 'setup.py' in listing or 'setup.cfg' in listing:
args.insert(1, os.getcwd()) args.insert(1, os.getcwd())
else: else:
logger.warning('No project to install.') logger.warning('No project to install.')
@ -244,16 +244,10 @@ def _install(dispatcher, args, **kw):
target = args[1] target = args[1]
# installing from a source dir or archive file? # installing from a source dir or archive file?
if os.path.isdir(target) or _is_archive_file(target): if os.path.isdir(target) or _is_archive_file(target):
if install_local_project(target): return not install_local_project(target)
return 0
else:
return 1
else: else:
# download from PyPI # download from PyPI
if install(target): return not install(target)
return 0
else:
return 1
@action_help(metadata_usage) @action_help(metadata_usage)
@ -263,12 +257,15 @@ def _metadata(dispatcher, args, **kw):
name = opts['args'][0] name = opts['args'][0]
dist = get_distribution(name, use_egg_info=True) dist = get_distribution(name, use_egg_info=True)
if dist is None: if dist is None:
logger.warning('%s not installed', name) logger.warning('%r not installed', name)
return return 1
else: elif os.path.isfile('setup.cfg'):
logger.info('searching local dir for metadata') logger.info('searching local dir for metadata')
dist = Distribution() dist = Distribution() # XXX use config module
dist.parse_config_files() dist.parse_config_files()
else:
logger.warning('no argument given and no local setup.cfg found')
return 1
metadata = dist.metadata metadata = dist.metadata
@ -299,11 +296,15 @@ def _remove(distpatcher, args, **kw):
else: else:
auto_confirm = False auto_confirm = False
retcode = 0
for dist in set(opts['args']): for dist in set(opts['args']):
try: try:
remove(dist, auto_confirm=auto_confirm) remove(dist, auto_confirm=auto_confirm)
except PackagingError: except PackagingError:
logger.warning('%s not installed', dist) logger.warning('%r not installed', dist)
retcode = 1
return retcode
@action_help(run_usage) @action_help(run_usage)
@ -339,14 +340,8 @@ def _run(dispatcher, args, **kw):
# XXX still need to be extracted from Distribution # XXX still need to be extracted from Distribution
dist.parse_config_files() dist.parse_config_files()
try: for cmd in dispatcher.commands:
for cmd in dispatcher.commands: dist.run_command(cmd, dispatcher.command_options[cmd])
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))
# XXX this is crappy # XXX this is crappy
return dist return dist
@ -358,19 +353,24 @@ def _list(dispatcher, args, **kw):
dists = get_distributions(use_egg_info=True) dists = get_distributions(use_egg_info=True)
if 'all' in opts or opts['args'] == []: if 'all' in opts or opts['args'] == []:
results = dists results = dists
listall = True
else: 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 number = 0
for dist in results: 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 number += 1
print()
if number == 0: 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: else:
print('Found %d projects installed.' % number) logger.info('Found %d projects installed.', number)
@action_help(search_usage) @action_help(search_usage)
@ -382,7 +382,8 @@ def _search(dispatcher, args, **kw):
""" """
#opts = _parse_args(args[1:], '', ['simple', 'xmlrpc']) #opts = _parse_args(args[1:], '', ['simple', 'xmlrpc'])
# 1. what kind of index is requested ? (xmlrpc / simple) # 1. what kind of index is requested ? (xmlrpc / simple)
raise NotImplementedError logger.error('not implemented')
return 1
actions = [ actions = [
@ -662,6 +663,7 @@ class Dispatcher:
def __call__(self): def __call__(self):
if self.action is None: if self.action is None:
return return
for action, desc, func in actions: for action, desc, func in actions:
if action == self.action: if action == self.action:
return func(self, self.args) return func(self, self.args)
@ -676,6 +678,12 @@ def main(args=None):
if dispatcher.action is None: if dispatcher.action is None:
return return
return dispatcher() return dispatcher()
except KeyboardInterrupt:
logger.info('interrupted')
return 1
except (IOError, os.error, PackagingError, CCompilerError) as exc:
logger.exception(exc)
return 1
finally: finally:
logger.setLevel(old_level) logger.setLevel(old_level)
logger.handlers[:] = old_handlers logger.handlers[:] = old_handlers

View file

@ -302,7 +302,7 @@ class TestDatabase(support.LoggingCatcher,
self.assertIsInstance(dist, Distribution) self.assertIsInstance(dist, Distribution)
if (dist.name in dict(fake_dists) and if (dist.name in dict(fake_dists) and
dist.path.startswith(self.fake_dists_path)): dist.path.startswith(self.fake_dists_path)):
found_dists.append((dist.name, dist.metadata['version'], )) found_dists.append((dist.name, dist.version))
else: else:
# check that it doesn't find anything more than this # check that it doesn't find anything more than this
self.assertFalse(dist.path.startswith(self.fake_dists_path)) self.assertFalse(dist.path.startswith(self.fake_dists_path))
@ -323,7 +323,7 @@ class TestDatabase(support.LoggingCatcher,
self.assertIsInstance(dist, (Distribution, EggInfoDistribution)) self.assertIsInstance(dist, (Distribution, EggInfoDistribution))
if (dist.name in dict(fake_dists) and if (dist.name in dict(fake_dists) and
dist.path.startswith(self.fake_dists_path)): dist.path.startswith(self.fake_dists_path)):
found_dists.append((dist.name, dist.metadata['version'])) found_dists.append((dist.name, dist.version))
else: else:
self.assertFalse(dist.path.startswith(self.fake_dists_path)) self.assertFalse(dist.path.startswith(self.fake_dists_path))
@ -489,17 +489,17 @@ class TestDatabase(support.LoggingCatcher,
checkLists([], _yield_distributions(False, False, sys.path)) 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) for dist in _yield_distributions(False, True, sys.path)
if dist.path.startswith(self.fake_dists_path)] if dist.path.startswith(self.fake_dists_path)]
checkLists(eggs, found) checkLists(eggs, found)
found = [(dist.name, dist.metadata['Version']) found = [(dist.name, dist.version)
for dist in _yield_distributions(True, False, sys.path) for dist in _yield_distributions(True, False, sys.path)
if dist.path.startswith(self.fake_dists_path)] if dist.path.startswith(self.fake_dists_path)]
checkLists(dists, found) checkLists(dists, found)
found = [(dist.name, dist.metadata['Version']) found = [(dist.name, dist.version)
for dist in _yield_distributions(True, True, sys.path) for dist in _yield_distributions(True, True, sys.path)
if dist.path.startswith(self.fake_dists_path)] if dist.path.startswith(self.fake_dists_path)]
checkLists(dists + eggs, found) checkLists(dists + eggs, found)

View file

@ -29,7 +29,7 @@ class InstalledDist:
self.metadata['Requires-Dist'] = deps self.metadata['Requires-Dist'] = deps
def __repr__(self): def __repr__(self):
return '<InstalledDist %s>' % self.metadata['Name'] return '<InstalledDist %r>' % self.metadata['Name']
class ToInstallDist: class ToInstallDist:

View file

@ -62,7 +62,9 @@ For an example, see the function test() at the end of the file.
import re import re
import os import os
import tempfile 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"] __all__ = ["Template"]
@ -245,22 +247,3 @@ def makepipeline(infile, steps, outfile):
cmdlist = trapcmd + '\n' + cmdlist + '\n' + rmcmd cmdlist = trapcmd + '\n' + cmdlist + '\n' + rmcmd
# #
return cmdlist 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("'", "'\"'\"'") + "'"

View file

@ -1,13 +1,9 @@
"""Class for printing reports on profiled python code.""" """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 # Written by James Roskind
# Based on prior profile module by Sjoerd Mullender... # Based on prior profile module by Sjoerd Mullender...
# which was hacked somewhat by: Guido van Rossum # which was hacked somewhat by: Guido van Rossum
"""Class for profiling Python code."""
# Copyright Disney Enterprises, Inc. All Rights Reserved. # Copyright Disney Enterprises, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement # Licensed to PSF under a Contributor Agreement
# #

View file

@ -6,13 +6,14 @@
# Posix compliance, split(), string arguments, and # Posix compliance, split(), string arguments, and
# iterator interface by Gustavo Niemeyer, April 2003. # iterator interface by Gustavo Niemeyer, April 2003.
import os.path import os
import re
import sys import sys
from collections import deque from collections import deque
from io import StringIO from io import StringIO
__all__ = ["shlex", "split"] __all__ = ["shlex", "split", "quote"]
class shlex: class shlex:
"A lexical analyzer class for simple shell-like syntaxes." "A lexical analyzer class for simple shell-like syntaxes."
@ -274,6 +275,21 @@ def split(s, comments=False, posix=True):
lex.commenters = '' lex.commenters = ''
return list(lex) 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 __name__ == '__main__':
if len(sys.argv) == 1: if len(sys.argv) == 1:
lexer = shlex() lexer = shlex()

View file

@ -4,17 +4,10 @@ Tests common to list and UserList.UserList
import sys import sys
import os import os
from functools import cmp_to_key
from test import support, seq_tests 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): class CommonTest(seq_tests.CommonTest):
@ -484,7 +477,7 @@ class CommonTest(seq_tests.CommonTest):
return 1 return 1
else: # a > b else: # a > b
return -1 return -1
u.sort(key=CmpToKey(revcmp)) u.sort(key=cmp_to_key(revcmp))
self.assertEqual(u, self.type2test([2,1,0,-1,-2])) self.assertEqual(u, self.type2test([2,1,0,-1,-2]))
# The following dumps core in unpatched Python 1.5: # The following dumps core in unpatched Python 1.5:
@ -497,7 +490,7 @@ class CommonTest(seq_tests.CommonTest):
else: # xmod > ymod else: # xmod > ymod
return 1 return 1
z = self.type2test(range(12)) z = self.type2test(range(12))
z.sort(key=CmpToKey(myComparison)) z.sort(key=cmp_to_key(myComparison))
self.assertRaises(TypeError, z.sort, 2) self.assertRaises(TypeError, z.sort, 2)
@ -509,7 +502,8 @@ class CommonTest(seq_tests.CommonTest):
return -1 return -1
else: # x > y else: # x > y
return 1 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) self.assertRaises(TypeError, z.sort, 42, 42, 42, 42)

View file

@ -1,7 +1,7 @@
import __future__
import os import os
import errno
import shutil
import unittest import unittest
import distutils.dir_util
import tempfile import tempfile
from test import support from test import support
@ -9,7 +9,7 @@ from test import support
import modulefinder import modulefinder
TEST_DIR = tempfile.mkdtemp() 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: # Each test description is a list of 5 items:
# #
@ -196,12 +196,17 @@ a/module.py
from . import bar from . import bar
"""] """]
def open_file(path): def open_file(path):
##print "#", os.path.abspath(path)
dirname = os.path.dirname(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") return open(path, "w")
def create_package(source): def create_package(source):
ofi = None ofi = None
try: try:
@ -216,6 +221,7 @@ def create_package(source):
if ofi: if ofi:
ofi.close() ofi.close()
class ModuleFinderTest(unittest.TestCase): class ModuleFinderTest(unittest.TestCase):
def _do_test(self, info, report=False): def _do_test(self, info, report=False):
import_this, modules, missing, maybe_missing, source = info import_this, modules, missing, maybe_missing, source = info
@ -234,19 +240,17 @@ class ModuleFinderTest(unittest.TestCase):
## import traceback; traceback.print_exc() ## import traceback; traceback.print_exc()
## sys.path = opath ## sys.path = opath
## return ## return
modules = set(modules) modules = sorted(set(modules))
found = set(mf.modules.keys()) found = sorted(mf.modules)
more = list(found - modules)
less = list(modules - found)
# check if we found what we expected, not more, not less # 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 # check for missing and maybe missing modules
bad, maybe = mf.any_missing_maybe() bad, maybe = mf.any_missing_maybe()
self.assertEqual(bad, missing) self.assertEqual(bad, missing)
self.assertEqual(maybe, maybe_missing) self.assertEqual(maybe, maybe_missing)
finally: finally:
distutils.dir_util.remove_tree(TEST_DIR) shutil.rmtree(TEST_DIR)
def test_package(self): def test_package(self):
self._do_test(package_test) self._do_test(package_test)
@ -254,25 +258,23 @@ class ModuleFinderTest(unittest.TestCase):
def test_maybe(self): def test_maybe(self):
self._do_test(maybe_test) 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): def test_absolute_imports(self):
self._do_test(maybe_test_new) self._do_test(absolute_import_test)
def test_absolute_imports(self): def test_relative_imports(self):
self._do_test(absolute_import_test) self._do_test(relative_import_test)
def test_relative_imports(self): def test_relative_imports_2(self):
self._do_test(relative_import_test) self._do_test(relative_import_test_2)
def test_relative_imports_2(self): def test_relative_imports_3(self):
self._do_test(relative_import_test_2) self._do_test(relative_import_test_3)
def test_relative_imports_3(self):
self._do_test(relative_import_test_3)
def test_main(): def test_main():
distutils.log.set_threshold(distutils.log.WARN)
support.run_unittest(ModuleFinderTest) support.run_unittest(ModuleFinderTest)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -79,20 +79,6 @@ class SimplePipeTests(unittest.TestCase):
with open(TESTFN) as f: with open(TESTFN) as f:
self.assertEqual(f.read(), d) 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): def testRepr(self):
t = pipes.Template() t = pipes.Template()
self.assertEqual(repr(t), "<Template instance, steps=[]>") self.assertEqual(repr(t), "<Template instance, steps=[]>")

View file

@ -1,6 +1,7 @@
import unittest import io
import os, sys, io
import shlex import shlex
import string
import unittest
from test import support from test import support
@ -173,6 +174,21 @@ class ShlexTest(unittest.TestCase):
"%s: %s != %s" % "%s: %s != %s" %
(self.data[i][0], l, self.data[i][1:])) (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 # Allow this test to be used with old shlex.py
if not getattr(shlex, "split", None): if not getattr(shlex, "split", None):
for methname in dir(ShlexTest): for methname in dir(ShlexTest):

View file

@ -2,18 +2,11 @@ from test import support
import random import random
import sys import sys
import unittest import unittest
from functools import cmp_to_key
verbose = support.verbose verbose = support.verbose
nerrors = 0 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): def check(tag, expected, raw, compare=None):
global nerrors global nerrors
@ -23,7 +16,7 @@ def check(tag, expected, raw, compare=None):
orig = raw[:] # save input in case of error orig = raw[:] # save input in case of error
if compare: if compare:
raw.sort(key=CmpToKey(compare)) raw.sort(key=cmp_to_key(compare))
else: else:
raw.sort() raw.sort()
@ -108,7 +101,7 @@ class TestBase(unittest.TestCase):
print(" Checking against an insane comparison function.") print(" Checking against an insane comparison function.")
print(" If the implementation isn't careful, this may segfault.") print(" If the implementation isn't careful, this may segfault.")
s = x[:] 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) check("an insane function left some permutation", x, s)
if len(x) >= 2: if len(x) >= 2:
@ -165,12 +158,12 @@ class TestBugs(unittest.TestCase):
L.pop() L.pop()
return (x > y) - (x < y) return (x > y) - (x < y)
L = [1,2] 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): def mutating_cmp(x, y):
L.append(3) L.append(3)
del L[:] del L[:]
return (x > y) - (x < y) 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] memorywaster = [memorywaster]
#============================================================================== #==============================================================================
@ -185,7 +178,7 @@ class TestDecorateSortUndecorate(unittest.TestCase):
def my_cmp(x, y): def my_cmp(x, y):
xlower, ylower = x.lower(), y.lower() xlower, ylower = x.lower(), y.lower()
return (xlower > ylower) - (xlower < ylower) return (xlower > ylower) - (xlower < ylower)
copy.sort(key=CmpToKey(my_cmp)) copy.sort(key=cmp_to_key(my_cmp))
def test_baddecorator(self): def test_baddecorator(self):
data = 'The quick Brown fox Jumped over The lazy Dog'.split() 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): def my_cmp_reversed(x, y):
x0, y0 = x[0], y[0] x0, y0 = x[0], y[0]
return (y0 > x0) - (y0 < x0) return (y0 > x0) - (y0 < x0)
data.sort(key=CmpToKey(my_cmp), reverse=True) data.sort(key=cmp_to_key(my_cmp), reverse=True)
copy1.sort(key=CmpToKey(my_cmp_reversed)) copy1.sort(key=cmp_to_key(my_cmp_reversed))
self.assertEqual(data, copy1) self.assertEqual(data, copy1)
copy2.sort(key=lambda x: x[0], reverse=True) copy2.sort(key=lambda x: x[0], reverse=True)
self.assertEqual(data, copy2) self.assertEqual(data, copy2)

View file

@ -172,10 +172,7 @@ class _RLock(_Verbose):
_PyRLock = _RLock _PyRLock = _RLock
def Condition(*args, **kwargs): class Condition(_Verbose):
return _Condition(*args, **kwargs)
class _Condition(_Verbose):
def __init__(self, lock=None, verbose=None): def __init__(self, lock=None, verbose=None):
_Verbose.__init__(self, verbose) _Verbose.__init__(self, verbose)
@ -308,10 +305,7 @@ class _Condition(_Verbose):
notifyAll = notify_all notifyAll = notify_all
def Semaphore(*args, **kwargs): class Semaphore(_Verbose):
return _Semaphore(*args, **kwargs)
class _Semaphore(_Verbose):
# After Tim Peters' semaphore class, but not quite the same (no maximum) # After Tim Peters' semaphore class, but not quite the same (no maximum)
@ -366,25 +360,19 @@ class _Semaphore(_Verbose):
self.release() self.release()
def BoundedSemaphore(*args, **kwargs): class BoundedSemaphore(Semaphore):
return _BoundedSemaphore(*args, **kwargs)
class _BoundedSemaphore(_Semaphore):
"""Semaphore that checks that # releases is <= # acquires""" """Semaphore that checks that # releases is <= # acquires"""
def __init__(self, value=1, verbose=None): def __init__(self, value=1, verbose=None):
_Semaphore.__init__(self, value, verbose) Semaphore.__init__(self, value, verbose)
self._initial_value = value self._initial_value = value
def release(self): def release(self):
if self._value >= self._initial_value: if self._value >= self._initial_value:
raise ValueError("Semaphore released too many times") raise ValueError("Semaphore released too many times")
return _Semaphore.release(self) return Semaphore.release(self)
def Event(*args, **kwargs): class Event(_Verbose):
return _Event(*args, **kwargs)
class _Event(_Verbose):
# After Tim Peters' event class (without is_posted()) # After Tim Peters' event class (without is_posted())
@ -918,10 +906,7 @@ class Thread(_Verbose):
# The timer class was contributed by Itamar Shtull-Trauring # The timer class was contributed by Itamar Shtull-Trauring
def Timer(*args, **kwargs): class Timer(Thread):
return _Timer(*args, **kwargs)
class _Timer(Thread):
"""Call a function after a specified number of seconds: """Call a function after a specified number of seconds:
t = Timer(30.0, f, args=[], kwargs={}) t = Timer(30.0, f, args=[], kwargs={})

View file

@ -244,6 +244,16 @@ Core and Builtins
Library 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 #12603: Fix pydoc.synopsis() on files with non-negative st_mtime.
- Issue #12514: Use try/finally to assure the timeit module restores garbage - Issue #12514: Use try/finally to assure the timeit module restores garbage

View file

@ -57,7 +57,7 @@ typedef struct {
int error; /* see WFERR_* values */ int error; /* see WFERR_* values */
int depth; int depth;
/* If fp == NULL, the following are valid: */ /* 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 *str;
PyObject *current_filename; PyObject *current_filename;
char *ptr; char *ptr;
@ -467,7 +467,7 @@ typedef WFILE RFILE; /* Same struct with different invariants */
static int static int
r_string(char *s, int n, RFILE *p) r_string(char *s, int n, RFILE *p)
{ {
char * ptr; char *ptr;
int read, left; int read, left;
if (!p->readable) { if (!p->readable) {
@ -566,7 +566,7 @@ r_long(RFILE *p)
static PyObject * static PyObject *
r_long64(RFILE *p) r_long64(RFILE *p)
{ {
PyObject * result = NULL; PyObject *result = NULL;
long lo4 = r_long(p); long lo4 = r_long(p);
long hi4 = r_long(p); long hi4 = r_long(p);

1
Tools/scripts/abitype.py Normal file → Executable file
View file

@ -1,3 +1,4 @@
#!/usr/bin/env python3
# This script converts a C file to use the PEP 384 type definition API # This script converts a C file to use the PEP 384 type definition API
# Usage: abitype.py < old_code > new_code # Usage: abitype.py < old_code > new_code
import re, sys import re, sys

0
Tools/scripts/cleanfuture.py Normal file → Executable file
View file

0
Tools/scripts/combinerefs.py Normal file → Executable file
View file

0
Tools/scripts/db2pickle.py Normal file → Executable file
View file

1
Tools/scripts/diff.py Normal file → Executable file
View file

@ -1,3 +1,4 @@
#!/usr/bin/env python3
""" Command line interface to difflib.py providing diffs in four formats: """ Command line interface to difflib.py providing diffs in four formats:
* ndiff: lists every line and highlights interline changes. * ndiff: lists every line and highlights interline changes.

0
Tools/scripts/find_recursionlimit.py Normal file → Executable file
View file

0
Tools/scripts/get-remote-certificate.py Normal file → Executable file
View file

25
Tools/scripts/mailerdaemon.py Normal file → Executable file
View file

@ -1,4 +1,5 @@
"""mailerdaemon - classes to parse mailer-daemon messages""" #!/usr/bin/env python3
"""Classes to parse mailer-daemon messages."""
import calendar import calendar
import email.message import email.message
@ -6,7 +7,10 @@ import re
import os import os
import sys import sys
Unparseable = 'mailerdaemon.Unparseable'
class Unparseable(Exception):
pass
class ErrorMessage(email.message.Message): class ErrorMessage(email.message.Message):
def __init__(self): def __init__(self):
@ -18,8 +22,10 @@ class ErrorMessage(email.message.Message):
if not sub: if not sub:
return 0 return 0
sub = sub.lower() sub = sub.lower()
if sub.startswith('waiting mail'): return 1 if sub.startswith('waiting mail'):
if 'warning' in sub: return 1 return 1
if 'warning' in sub:
return 1
self.sub = sub self.sub = sub
return 0 return 0
@ -145,14 +151,17 @@ def emparse_list(fp, sub):
errors.append(' '.join((email.strip()+': '+reason).split())) errors.append(' '.join((email.strip()+': '+reason).split()))
return errors return errors
EMPARSERS = [emparse_list, ] EMPARSERS = [emparse_list]
def sort_numeric(a, b): def sort_numeric(a, b):
a = int(a) a = int(a)
b = int(b) b = int(b)
if a < b: return -1 if a < b:
elif a > b: return 1 return -1
else: return 0 elif a > b:
return 1
else:
return 0
def parsedir(dir, modify): def parsedir(dir, modify):
os.chdir(dir) os.chdir(dir)

1
Tools/scripts/make_ctype.py Normal file → Executable file
View file

@ -1,3 +1,4 @@
#!/usr/bin/env python3
"""Script that generates the ctype.h-replacement in stringobject.c.""" """Script that generates the ctype.h-replacement in stringobject.c."""
NAMES = ("LOWER", "UPPER", "ALPHA", "DIGIT", "XDIGIT", "ALNUM", "SPACE") NAMES = ("LOWER", "UPPER", "ALPHA", "DIGIT", "XDIGIT", "ALNUM", "SPACE")

0
Tools/scripts/md5sum.py Normal file → Executable file
View file

1
Tools/scripts/patchcheck.py Normal file → Executable file
View file

@ -1,3 +1,4 @@
#!/usr/bin/env python3
import re import re
import sys import sys
import shutil import shutil

0
Tools/scripts/pickle2db.py Normal file → Executable file
View file

0
Tools/scripts/pysource.py Normal file → Executable file
View file

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# Make a reST file compliant to our pre-commit hook. # Make a reST file compliant to our pre-commit hook.
# Currently just remove trailing whitespace. # Currently just remove trailing whitespace.

0
Tools/scripts/svneol.py Normal file → Executable file
View file