Commit 8f374fd1 authored by Éric Araujo's avatar Éric Araujo

Branch merge

parents 4f25d149 5172db37
......@@ -347,6 +347,8 @@ is a separate error indicator for each thread.
error checking. *fd* should be a valid file descriptor. The function should
only be called from the main thread.
.. versionadded:: 2.6
.. cfunction:: PyObject* PyErr_NewException(char *name, PyObject *base, PyObject *dict)
......
......@@ -474,7 +474,7 @@ the fork, and releasing them afterwards. In addition, it resets any
:ref:`lock-objects` in the child. When extending or embedding Python, there
is no way to inform Python of additional (non-Python) locks that need to be
acquired before or reset after a fork. OS facilities such as
:cfunc:`posix_atfork` would need to be used to accomplish the same thing.
:cfunc:`pthread_atfork` would need to be used to accomplish the same thing.
Additionally, when extending or embedding Python, calling :cfunc:`fork`
directly rather than through :func:`os.fork` (and returning to or calling
into Python) may result in a deadlock by one of Python's internal locks
......@@ -906,7 +906,7 @@ a worker thread and the actual call than made at the earliest convenience by the
main thread where it has possession of the global interpreter lock and can
perform any Python API calls.
.. cfunction:: void Py_AddPendingCall( int (*func)(void *, void *arg) )
.. cfunction:: int Py_AddPendingCall(int (*func)(void *), void *arg)
.. index:: single: Py_AddPendingCall()
......
......@@ -108,6 +108,9 @@ Object Protocol
Python expression ``o1 op o2``, where ``op`` is the operator corresponding to
*opid*.
.. note::
If *o1* and *o2* are the same object, :cfunc:`PyObject_RichCompareBool`
will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`.
.. cfunction:: int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result)
......
......@@ -152,7 +152,7 @@ The directives are:
Describes global data in a module, including both variables and values used
as "defined constants." Class and object attributes are not documented
using this environment.
using this directive.
.. describe:: exception
......@@ -165,7 +165,7 @@ The directives are:
parameters, enclosing optional parameters in brackets. Default values can be
given if it enhances clarity. For example::
.. function:: Timer.repeat([repeat=3[, number=1000000]])
.. function:: repeat([repeat=3[, number=1000000]])
Object methods are not documented using this directive. Bound object methods
placed in the module namespace as part of the public interface of the module
......@@ -186,13 +186,30 @@ The directives are:
Describes an object data attribute. The description should include
information about the type of the data to be expected and whether it may be
changed directly.
changed directly. This directive should be nested in a class directive,
like in this example::
.. class:: Spam
Description of the class.
.. data:: ham
Description of the attribute.
If is also possible to document an attribute outside of a class directive,
for example if the documentation for different attributes and methods is
split in multiple sections. The class name should then be included
explicitly::
.. data:: Spam.eggs
.. describe:: method
Describes an object method. The parameters should not include the ``self``
parameter. The description should include similar information to that
described for ``function``.
described for ``function``. This method should be nested in a class
method, like in the example above.
.. describe:: opcode
......
......@@ -308,7 +308,7 @@ http://www.pythonology.com/success
buying, but the publishers have made the first chapter available on
the Web.
http://home.pacbell.net/ouster/scripting.html
http://www.tcl.tk/doc/scripting.html
John Ousterhout's white paper on scripting is a good argument for the utility of
scripting languages, though naturally enough, he emphasizes Tcl, the language he
developed. Most of the arguments would apply to any scripting language.
......
:mod:`argparse` --- Parser for command line options, arguments and sub-commands
:mod:`argparse` --- Parser for command-line options, arguments and sub-commands
===============================================================================
.. module:: argparse
:synopsis: Command-line option and argument parsing library.
:synopsis: Command-line option and argument-parsing library.
.. moduleauthor:: Steven Bethard <steven.bethard@gmail.com>
.. versionadded:: 2.7
.. sectionauthor:: Steven Bethard <steven.bethard@gmail.com>
The :mod:`argparse` module makes it easy to write user friendly command line
The :mod:`argparse` module makes it easy to write user-friendly command-line
interfaces. The program defines what arguments it requires, and :mod:`argparse`
will figure out how to parse those out of :data:`sys.argv`. The :mod:`argparse`
module also automatically generates help and usage messages and issues errors
......@@ -75,7 +75,7 @@ The first step in using the :mod:`argparse` is creating an
>>> parser = argparse.ArgumentParser(description='Process some integers.')
The :class:`ArgumentParser` object will hold all the information necessary to
parse the command line into python data types.
parse the command line into Python data types.
Adding arguments
......@@ -93,7 +93,7 @@ used when :meth:`~ArgumentParser.parse_args` is called. For example::
... const=sum, default=max,
... help='sum the integers (default: find the max)')
Later, calling :meth:`parse_args` will return an object with
Later, calling :meth:`~ArgumentParser.parse_args` will return an object with
two attributes, ``integers`` and ``accumulate``. The ``integers`` attribute
will be a list of one or more ints, and the ``accumulate`` attribute will be
either the :func:`sum` function, if ``--sum`` was specified at the command line,
......@@ -104,10 +104,10 @@ Parsing arguments
^^^^^^^^^^^^^^^^^
:class:`ArgumentParser` parses args through the
:meth:`~ArgumentParser.parse_args` method. This will inspect the command-line,
:meth:`~ArgumentParser.parse_args` method. This will inspect the command line,
convert each arg to the appropriate type and then invoke the appropriate action.
In most cases, this means a simple namespace object will be built up from
attributes parsed out of the command-line::
attributes parsed out of the command line::
>>> parser.parse_args(['--sum', '7', '-1', '42'])
Namespace(accumulate=<built-in function sum>, integers=[7, -1, 42])
......@@ -120,9 +120,7 @@ command-line args from :data:`sys.argv`.
ArgumentParser objects
----------------------
.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], \
[argument_default], [parents], [prefix_chars], \
[conflict_handler], [formatter_class])
.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], [argument_default], [parents], [prefix_chars], [conflict_handler], [formatter_class])
Create a new :class:`ArgumentParser` object. Each parameter has its own more
detailed description below, but in short they are:
......@@ -217,7 +215,7 @@ the parser's help message. For example, consider a file named
parser.add_argument('--foo', help='foo help')
args = parser.parse_args()
If ``-h`` or ``--help`` is supplied is at the command-line, the ArgumentParser
If ``-h`` or ``--help`` is supplied at the command line, the ArgumentParser
help will be printed::
$ python myprogram.py --help
......@@ -291,10 +289,10 @@ arguments they contain. For example::
Namespace(f='bar')
Arguments read from a file must by default be one per line (but see also
:meth:`convert_arg_line_to_args`) and are treated as if they were in the same
place as the original file referencing argument on the command line. So in the
example above, the expression ``['-f', 'foo', '@args.txt']`` is considered
equivalent to the expression ``['-f', 'foo', '-f', 'bar']``.
:meth:`~ArgumentParser.convert_arg_line_to_args`) and are treated as if they
were in the same place as the original file referencing argument on the command
line. So in the example above, the expression ``['-f', 'foo', '@args.txt']``
is considered equivalent to the expression ``['-f', 'foo', '-f', 'bar']``.
The ``fromfile_prefix_chars=`` argument defaults to ``None``, meaning that
arguments will never be treated as file references.
......@@ -304,11 +302,12 @@ argument_default
^^^^^^^^^^^^^^^^
Generally, argument defaults are specified either by passing a default to
:meth:`add_argument` or by calling the :meth:`set_defaults` methods with a
specific set of name-value pairs. Sometimes however, it may be useful to
specify a single parser-wide default for arguments. This can be accomplished by
passing the ``argument_default=`` keyword argument to :class:`ArgumentParser`.
For example, to globally suppress attribute creation on :meth:`parse_args`
:meth:`~ArgumentParser.add_argument` or by calling the
:meth:`~ArgumentParser.set_defaults` methods with a specific set of name-value
pairs. Sometimes however, it may be useful to specify a single parser-wide
default for arguments. This can be accomplished by passing the
``argument_default=`` keyword argument to :class:`ArgumentParser`. For example,
to globally suppress attribute creation on :meth:`~ArgumentParser.parse_args`
calls, we supply ``argument_default=SUPPRESS``::
>>> parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
......@@ -358,11 +357,14 @@ formatter_class
:class:`ArgumentParser` objects allow the help formatting to be customized by
specifying an alternate formatting class. Currently, there are three such
classes: :class:`argparse.RawDescriptionHelpFormatter`,
:class:`argparse.RawTextHelpFormatter` and
:class:`argparse.ArgumentDefaultsHelpFormatter`. The first two allow more
control over how textual descriptions are displayed, while the last
automatically adds information about argument default values.
classes:
.. class:: RawDescriptionHelpFormatter
RawTextHelpFormatter
ArgumentDefaultsHelpFormatter
The first two allow more control over how textual descriptions are displayed,
while the last automatically adds information about argument default values.
By default, :class:`ArgumentParser` objects line-wrap the description_ and
epilog_ texts in command-line help messages::
......@@ -387,7 +389,7 @@ epilog_ texts in command-line help messages::
likewise for this epilog whose whitespace will be cleaned up and whose words
will be wrapped across a couple lines
Passing :class:`argparse.RawDescriptionHelpFormatter` as ``formatter_class=``
Passing :class:`~argparse.RawDescriptionHelpFormatter` as ``formatter_class=``
indicates that description_ and epilog_ are already correctly formatted and
should not be line-wrapped::
......@@ -570,27 +572,25 @@ your usage messages.
The add_argument() method
-------------------------
.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], \
[const], [default], [type], [choices], [required], \
[help], [metavar], [dest])
.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], [const], [default], [type], [choices], [required], [help], [metavar], [dest])
Define how a single command line argument should be parsed. Each parameter
Define how a single command-line argument should be parsed. Each parameter
has its own more detailed description below, but in short they are:
* `name or flags`_ - Either a name or a list of option strings, e.g. ``foo``
or ``-f, --foo``
or ``-f, --foo``.
* action_ - The basic type of action to be taken when this argument is
encountered at the command-line.
encountered at the command line.
* nargs_ - The number of command-line arguments that should be consumed.
* const_ - A constant value required by some action_ and nargs_ selections.
* default_ - The value produced if the argument is absent from the
command-line.
command line.
* type_ - The type to which the command-line arg should be converted.
* type_ - The type to which the command-line argument should be converted.
* choices_ - A container of the allowable values for the argument.
......@@ -610,11 +610,12 @@ The following sections describe how each of these are used.
name or flags
^^^^^^^^^^^^^
The :meth:`add_argument` method must know whether an optional argument, like
``-f`` or ``--foo``, or a positional argument, like a list of filenames, is
expected. The first arguments passed to :meth:`add_argument` must therefore be
either a series of flags, or a simple argument name. For example, an optional
argument could be created like::
The :meth:`~ArgumentParser.add_argument` method must know whether an optional
argument, like ``-f`` or ``--foo``, or a positional argument, like a list of
filenames, is expected. The first arguments passed to
:meth:`~ArgumentParser.add_argument` must therefore be either a series of
flags, or a simple argument name. For example, an optional argument could
be created like::
>>> parser.add_argument('-f', '--foo')
......@@ -622,8 +623,9 @@ while a positional argument could be created like::
>>> parser.add_argument('bar')
When :meth:`parse_args` is called, optional arguments will be identified by the
``-`` prefix, and the remaining arguments will be assumed to be positional::
When :meth:`~ArgumentParser.parse_args` is called, optional arguments will be
identified by the ``-`` prefix, and the remaining arguments will be assumed to
be positional::
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-f', '--foo')
......@@ -643,11 +645,11 @@ action
:class:`ArgumentParser` objects associate command-line args with actions. These
actions can do just about anything with the command-line args associated with
them, though most actions simply add an attribute to the object returned by
:meth:`parse_args`. The ``action`` keyword argument specifies how the
command-line args should be handled. The supported actions are:
:meth:`~ArgumentParser.parse_args`. The ``action`` keyword argument specifies
how the command-line args should be handled. The supported actions are:
* ``'store'`` - This just stores the argument's value. This is the default
action. For example::
action. For example::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
......@@ -655,9 +657,9 @@ command-line args should be handled. The supported actions are:
Namespace(foo='1')
* ``'store_const'`` - This stores the value specified by the const_ keyword
argument. (Note that the const_ keyword argument defaults to the rather
unhelpful ``None``.) The ``'store_const'`` action is most commonly used with
optional arguments that specify some sort of flag. For example::
argument. (Note that the const_ keyword argument defaults to the rather
unhelpful ``None``.) The ``'store_const'`` action is most commonly used with
optional arguments that specify some sort of flag. For example::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='store_const', const=42)
......@@ -696,8 +698,8 @@ command-line args should be handled. The supported actions are:
Namespace(types=[<type 'str'>, <type 'int'>])
* ``'version'`` - This expects a ``version=`` keyword argument in the
:meth:`add_argument` call, and prints version information and exits when
invoked.
:meth:`~ArgumentParser.add_argument` call, and prints version information
and exits when invoked.
>>> import argparse
>>> parser = argparse.ArgumentParser(prog='PROG')
......@@ -713,11 +715,12 @@ the Action API. The easiest way to do this is to extend
* ``parser`` - The ArgumentParser object which contains this action.
* ``namespace`` - The namespace object that will be returned by
:meth:`parse_args`. Most actions add an attribute to this object.
:meth:`~ArgumentParser.parse_args`. Most actions add an attribute to this
object.
* ``values`` - The associated command-line args, with any type-conversions
applied. (Type-conversions are specified with the type_ keyword argument to
:meth:`add_argument`.
:meth:`~ArgumentParser.add_argument`.
* ``option_string`` - The option string that was used to invoke this action.
The ``option_string`` argument is optional, and will be absent if the action
......@@ -745,10 +748,10 @@ nargs
ArgumentParser objects usually associate a single command-line argument with a
single action to be taken. The ``nargs`` keyword argument associates a
different number of command-line arguments with a single action.. The supported
different number of command-line arguments with a single action. The supported
values are:
* N (an integer). N args from the command-line will be gathered together into a
* N (an integer). N args from the command line will be gathered together into a
list. For example::
>>> parser = argparse.ArgumentParser()
......@@ -760,7 +763,7 @@ values are:
Note that ``nargs=1`` produces a list of one item. This is different from
the default, in which the item is produced by itself.
* ``'?'``. One arg will be consumed from the command-line if possible, and
* ``'?'``. One arg will be consumed from the command line if possible, and
produced as a single item. If no command-line arg is present, the value from
default_ will be produced. Note that for optional arguments, there is an
additional case - the option string is present but not followed by a
......@@ -824,21 +827,20 @@ will be consumed and a single item (not a list) will be produced.
const
^^^^^
The ``const`` argument of :meth:`add_argument` is used to hold constant values
that are not read from the command line but are required for the various
ArgumentParser actions. The two most common uses of it are:
The ``const`` argument of :meth:`~ArgumentParser.add_argument` is used to hold
constant values that are not read from the command line but are required for
the various :class:`ArgumentParser` actions. The two most common uses of it are:
* When :meth:`add_argument` is called with ``action='store_const'`` or
``action='append_const'``. These actions add the ``const`` value to one of
the attributes of the object returned by :meth:`parse_args`. See the action_
description for examples.
* When :meth:`~ArgumentParser.add_argument` is called with
``action='store_const'`` or ``action='append_const'``. These actions add the
``const`` value to one of the attributes of the object returned by :meth:`~ArgumentParser.parse_args`. See the action_ description for examples.
* When :meth:`add_argument` is called with option strings (like ``-f`` or
``--foo``) and ``nargs='?'``. This creates an optional argument that can be
followed by zero or one command-line args. When parsing the command-line, if
the option string is encountered with no command-line arg following it, the
value of ``const`` will be assumed instead. See the nargs_ description for
examples.
* When :meth:`~ArgumentParser.add_argument` is called with option strings
(like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional
argument that can be followed by zero or one command-line args.
When parsing the command line, if the option string is encountered with no
command-line arg following it, the value of ``const`` will be assumed instead.
See the nargs_ description for examples.
The ``const`` keyword argument defaults to ``None``.
......@@ -847,10 +849,11 @@ default
^^^^^^^
All optional arguments and some positional arguments may be omitted at the
command-line. The ``default`` keyword argument of :meth:`add_argument`, whose
value defaults to ``None``, specifies what value should be used if the
command-line arg is not present. For optional arguments, the ``default`` value
is used when the option string was not present at the command line::
command line. The ``default`` keyword argument of
:meth:`~ArgumentParser.add_argument`, whose value defaults to ``None``,
specifies what value should be used if the command-line arg is not present.
For optional arguments, the ``default`` value is used when the option string
was not present at the command line::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', default=42)
......@@ -887,9 +890,9 @@ type
By default, ArgumentParser objects read command-line args in as simple strings.
However, quite often the command-line string should instead be interpreted as
another type, like a :class:`float`, :class:`int` or :class:`file`. The
``type`` keyword argument of :meth:`add_argument` allows any necessary
type-checking and type-conversions to be performed. Many common built-in types
can be used directly as the value of the ``type`` argument::
``type`` keyword argument of :meth:`~ArgumentParser.add_argument` allows any
necessary type-checking and type-conversions to be performed. Many common
built-in types can be used directly as the value of the ``type`` argument::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('foo', type=int)
......@@ -945,9 +948,9 @@ choices
Some command-line args should be selected from a restricted set of values.
These can be handled by passing a container object as the ``choices`` keyword
argument to :meth:`add_argument`. When the command-line is parsed, arg values
will be checked, and an error message will be displayed if the arg was not one
of the acceptable values::
argument to :meth:`~ArgumentParser.add_argument`. When the command line is
parsed, arg values will be checked, and an error message will be displayed if
the arg was not one of the acceptable values::
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('foo', choices='abc')
......@@ -977,10 +980,10 @@ etc. are all supported.
required
^^^^^^^^
In general, the argparse module assumes that flags like ``-f`` and ``--bar``
indicate *optional* arguments, which can always be omitted at the command-line.
In general, the :mod:`argparse` module assumes that flags like ``-f`` and ``--bar``
indicate *optional* arguments, which can always be omitted at the command line.
To make an option *required*, ``True`` can be specified for the ``required=``
keyword argument to :meth:`add_argument`::
keyword argument to :meth:`~ArgumentParser.add_argument`::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', required=True)
......@@ -990,8 +993,9 @@ keyword argument to :meth:`add_argument`::
usage: argparse.py [-h] [--foo FOO]
argparse.py: error: option --foo is required
As the example shows, if an option is marked as ``required``, :meth:`parse_args`
will report an error if that option is not present at the command line.
As the example shows, if an option is marked as ``required``,
:meth:`~ArgumentParser.parse_args` will report an error if that option is not
present at the command line.
.. note::
......@@ -1004,7 +1008,7 @@ help
The ``help`` value is a string containing a brief description of the argument.
When a user requests help (usually by using ``-h`` or ``--help`` at the
command-line), these ``help`` descriptions will be displayed with each
command line), these ``help`` descriptions will be displayed with each
argument::
>>> parser = argparse.ArgumentParser(prog='frobble')
......@@ -1025,7 +1029,7 @@ argument::
The ``help`` strings can include various format specifiers to avoid repetition
of things like the program name or the argument default_. The available
specifiers include the program name, ``%(prog)s`` and most keyword arguments to
:meth:`add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.::
:meth:`~ArgumentParser.add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.::
>>> parser = argparse.ArgumentParser(prog='frobble')
>>> parser.add_argument('bar', nargs='?', type=int, default=42,
......@@ -1085,8 +1089,8 @@ An alternative name can be specified with ``metavar``::
--foo YYY
Note that ``metavar`` only changes the *displayed* name - the name of the
attribute on the :meth:`parse_args` object is still determined by the dest_
value.
attribute on the :meth:`~ArgumentParser.parse_args` object is still determined
by the dest_ value.
Different values of ``nargs`` may cause the metavar to be used multiple times.
Providing a tuple to ``metavar`` specifies a different display for each of the
......@@ -1108,10 +1112,11 @@ dest
^^^^
Most :class:`ArgumentParser` actions add some value as an attribute of the
object returned by :meth:`parse_args`. The name of this attribute is determined
by the ``dest`` keyword argument of :meth:`add_argument`. For positional
argument actions, ``dest`` is normally supplied as the first argument to
:meth:`add_argument`::
object returned by :meth:`~ArgumentParser.parse_args`. The name of this
attribute is determined by the ``dest`` keyword argument of
:meth:`~ArgumentParser.add_argument`. For positional argument actions,
``dest`` is normally supplied as the first argument to
:meth:`~ArgumentParser.add_argument`::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('bar')
......@@ -1162,9 +1167,9 @@ The parse_args() method
Option value syntax
^^^^^^^^^^^^^^^^^^^
The :meth:`parse_args` method supports several ways of specifying the value of
an option (if it takes one). In the simplest case, the option and its value are
passed as two separate arguments::
The :meth:`~ArgumentParser.parse_args` method supports several ways of
specifying the value of an option (if it takes one). In the simplest case, the
option and its value are passed as two separate arguments::
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x')
......@@ -1175,7 +1180,7 @@ passed as two separate arguments::
Namespace(foo='FOO', x=None)
For long options (options with names longer than a single character), the option
and value can also be passed as a single command line argument, using ``=`` to
and value can also be passed as a single command-line argument, using ``=`` to
separate them::
>>> parser.parse_args('--foo=FOO'.split())
......@@ -1201,10 +1206,10 @@ as long as only the last option (or none of them) requires a value::
Invalid arguments
^^^^^^^^^^^^^^^^^
While parsing the command-line, ``parse_args`` checks for a variety of errors,
including ambiguous options, invalid types, invalid options, wrong number of
positional arguments, etc. When it encounters such an error, it exits and
prints the error along with a usage message::
While parsing the command line, :meth:`~ArgumentParser.parse_args` checks for a
variety of errors, including ambiguous options, invalid types, invalid options,
wrong number of positional arguments, etc. When it encounters such an error,
it exits and prints the error along with a usage message::
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo', type=int)
......@@ -1229,13 +1234,13 @@ prints the error along with a usage message::
Arguments containing ``"-"``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``parse_args`` method attempts to give errors whenever the user has clearly
made a mistake, but some situations are inherently ambiguous. For example, the
command-line arg ``'-1'`` could either be an attempt to specify an option or an
attempt to provide a positional argument. The ``parse_args`` method is cautious
here: positional arguments may only begin with ``'-'`` if they look like
negative numbers and there are no options in the parser that look like negative
numbers::
The :meth:`~ArgumentParser.parse_args` method attempts to give errors whenever
the user has clearly made a mistake, but some situations are inherently
ambiguous. For example, the command-line arg ``'-1'`` could either be an
attempt to specify an option or an attempt to provide a positional argument.
The :meth:`~ArgumentParser.parse_args` method is cautious here: positional
arguments may only begin with ``'-'`` if they look like negative numbers and
there are no options in the parser that look like negative numbers::
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x')
......@@ -1269,7 +1274,8 @@ numbers::
If you have positional arguments that must begin with ``'-'`` and don't look
like negative numbers, you can insert the pseudo-argument ``'--'`` which tells
``parse_args`` that everything after that is a positional argument::
:meth:`~ArgumentParser.parse_args` that everything after that is a positional
argument::
>>> parser.parse_args(['--', '-f'])
Namespace(foo='-f', one=None)
......@@ -1278,8 +1284,8 @@ like negative numbers, you can insert the pseudo-argument ``'--'`` which tells
Argument abbreviations
^^^^^^^^^^^^^^^^^^^^^^
The :meth:`parse_args` method allows long options to be abbreviated if the
abbreviation is unambiguous::
The :meth:`~ArgumentParser.parse_args` method allows long options to be
abbreviated if the abbreviation is unambiguous::
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-bacon')
......@@ -1300,7 +1306,8 @@ Beyond ``sys.argv``
Sometimes it may be useful to have an ArgumentParser parse args other than those
of :data:`sys.argv`. This can be accomplished by passing a list of strings to
``parse_args``. This is useful for testing at the interactive prompt::
:meth:`~ArgumentParser.parse_args`. This is useful for testing at the
interactive prompt::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument(
......@@ -1318,11 +1325,11 @@ of :data:`sys.argv`. This can be accomplished by passing a list of strings to
The Namespace object
^^^^^^^^^^^^^^^^^^^^
By default, :meth:`parse_args` will return a new object of type :class:`Namespace`
where the necessary attributes have been set. This class is deliberately simple,
just an :class:`object` subclass with a readable string representation. If you
prefer to have dict-like view of the attributes, you can use the standard Python
idiom via :func:`vars`::
By default, :meth:`~ArgumentParser.parse_args` will return a new object of type
:class:`Namespace` where the necessary attributes have been set. This class is
deliberately simple, just an :class:`object` subclass with a readable string
representation. If you prefer to have dict-like view of the attributes, you
can use the standard Python idiom via :func:`vars`::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
......@@ -1361,9 +1368,9 @@ Sub-commands
:class:`ArgumentParser` supports the creation of such sub-commands with the
:meth:`add_subparsers` method. The :meth:`add_subparsers` method is normally
called with no arguments and returns an special action object. This object
has a single method, ``add_parser``, which takes a command name and any
:class:`ArgumentParser` constructor arguments, and returns an
:class:`ArgumentParser` object that can be modified as usual.
has a single method, :meth:`~ArgumentParser.add_parser`, which takes a
command name and any :class:`ArgumentParser` constructor arguments, and
returns an :class:`ArgumentParser` object that can be modified as usual.
Some example usage::
......@@ -1397,7 +1404,7 @@ Sub-commands
for that particular parser will be printed. The help message will not
include parent parser or sibling parser messages. (A help message for each
subparser command, however, can be given by supplying the ``help=`` argument
to ``add_parser`` as above.)
to :meth:`add_parser` as above.)
::
......@@ -1587,9 +1594,9 @@ Mutual exclusion
.. method:: add_mutually_exclusive_group(required=False)
Create a mutually exclusive group. argparse will make sure that only one of
the arguments in the mutually exclusive group was present on the command
line::
Create a mutually exclusive group. :mod:`argparse` will make sure that only
one of the arguments in the mutually exclusive group was present on the
command line::
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> group = parser.add_mutually_exclusive_group()
......@@ -1616,7 +1623,8 @@ Mutual exclusion
PROG: error: one of the arguments --foo --bar is required
Note that currently mutually exclusive argument groups do not support the
*title* and *description* arguments of :meth:`add_argument_group`.
*title* and *description* arguments of
:meth:`~ArgumentParser.add_argument_group`.
Parser defaults
......@@ -1626,8 +1634,8 @@ Parser defaults
Most of the time, the attributes of the object returned by :meth:`parse_args`
will be fully determined by inspecting the command-line args and the argument
actions. :meth:`ArgumentParser.set_defaults` allows some additional
attributes that are determined without any inspection of the command-line to
actions. :meth:`set_defaults` allows some additional
attributes that are determined without any inspection of the command line to
be added::
>>> parser = argparse.ArgumentParser()
......@@ -1663,9 +1671,9 @@ Parser defaults
Printing help
^^^^^^^^^^^^^
In most typical applications, :meth:`parse_args` will take care of formatting
and printing any usage or error messages. However, several formatting methods
are available:
In most typical applications, :meth:`~ArgumentParser.parse_args` will take
care of formatting and printing any usage or error messages. However, several
formatting methods are available:
.. method:: ArgumentParser.print_usage(file=None)
......@@ -1698,9 +1706,9 @@ Partial parsing
.. method:: ArgumentParser.parse_known_args(args=None, namespace=None)
Sometimes a script may only parse a few of the command line arguments, passing
Sometimes a script may only parse a few of the command-line arguments, passing
the remaining arguments on to another script or program. In these cases, the
:meth:`parse_known_args` method can be useful. It works much like
:meth:`~ArgumentParser.parse_known_args` method can be useful. It works much like
:meth:`~ArgumentParser.parse_args` except that it does not produce an error when
extra arguments are present. Instead, it returns a two item tuple containing
the populated namespace and the list of remaining argument strings.
......@@ -1757,17 +1765,17 @@ Exiting methods
Upgrading optparse code
-----------------------
Originally, the argparse module had attempted to maintain compatibility with
optparse. However, optparse was difficult to extend transparently, particularly
with the changes required to support the new ``nargs=`` specifiers and better
usage messages. When most everything in optparse had either been copy-pasted
over or monkey-patched, it no longer seemed practical to try to maintain the
backwards compatibility.
Originally, the :mod:`argparse` module had attempted to maintain compatibility
with :mod:`optparse`. However, :mod:`optparse` was difficult to extend
transparently, particularly with the changes required to support the new
``nargs=`` specifiers and better usage messages. When most everything in
:mod:`optparse` had either been copy-pasted over or monkey-patched, it no
longer seemed practical to try to maintain the backwards compatibility.
A partial upgrade path from optparse to argparse:
A partial upgrade path from :mod:`optparse` to :mod:`argparse`:
* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument`
calls.
* Replace all :meth:`optparse.OptionParser.add_option` calls with
:meth:`ArgumentParser.add_argument` calls.
* Replace ``options, args = parser.parse_args()`` with ``args =
parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument`
......@@ -1784,7 +1792,7 @@ A partial upgrade path from optparse to argparse:
:exc:`ArgumentError`.
* Replace strings with implicit arguments such as ``%default`` or ``%prog`` with
the standard python syntax to use dictionaries to format strings, that is,
the standard Python syntax to use dictionaries to format strings, that is,
``%(default)s`` and ``%(prog)s``.
* Replace the OptionParser constructor ``version`` argument with a call to
......
......@@ -818,6 +818,9 @@ semantics pass-in keyword arguments using a regular unordered dictionary.
`Equivalent OrderedDict recipe <http://code.activestate.com/recipes/576693/>`_
that runs on Python 2.4 or later.
:class:`OrderedDict` Examples and Recipes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Since an ordered dictionary remembers its insertion order, it can be used
in conjuction with sorting to make a sorted dictionary::
......@@ -846,12 +849,29 @@ If a new entry overwrites an existing entry, the
original insertion position is changed and moved to the end::
class LastUpdatedOrderedDict(OrderedDict):
'Store items in the order the keys were last added'
def __setitem__(self, key, value):
if key in self:
del self[key]
OrderedDict.__setitem__(self, key, value)
An ordered dictionary can combined with the :class:`Counter` class
so that the counter remembers the order elements are first encountered::
class OrderedCounter(Counter, OrderedDict):
'Counter that remembers the order elements are first encountered'
def __init__(self, iterable=None, **kwds):
OrderedDict.__init__(self)
Counter.__init__(self, iterable, **kwds)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
.. _abstract-base-classes:
......
......@@ -96,6 +96,9 @@ write-back, as will be the keys within each section.
This class does not
support the magical interpolation behavior.
All option names are passed through the :meth:`optionxform` method. Its
default implementation converts option names to lower case.
.. versionadded:: 2.3
.. versionchanged:: 2.6
......@@ -116,10 +119,9 @@ write-back, as will be the keys within each section.
*defaults*.
All option names used in interpolation will be passed through the
:meth:`optionxform` method just like any other option name reference. For
example, using the default implementation of :meth:`optionxform` (which converts
option names to lower case), the values ``foo %(bar)s`` and ``foo %(BAR)s`` are
equivalent.
:meth:`optionxform` method just like any other option name reference. Using
the default implementation of :meth:`optionxform`, the values ``foo %(bar)s``
and ``foo %(BAR)s`` are equivalent.
.. versionadded:: 2.3
......
......@@ -74,15 +74,29 @@ in :mod:`logging` itself) and defining handlers which are declared either in
.. versionadded:: 2.7
.. function:: fileConfig(fname[, defaults])
.. function:: fileConfig(fname, defaults=None, disable_existing_loggers=True)
Reads the logging configuration from a :mod:`configparser`\-format file named
*fname*. This function can be called several times from an application,
allowing an end user to select from various pre-canned
Reads the logging configuration from a :mod:`configparser`\-format file
named *fname*. This function can be called several times from an
application, allowing an end user to select from various pre-canned
configurations (if the developer provides a mechanism to present the choices
and load the chosen configuration). Defaults to be passed to the ConfigParser
can be specified in the *defaults* argument.
and load the chosen configuration).
:param defaults: Defaults to be passed to the ConfigParser can be specified
in this argument.
:param disable_existing_loggers: If specified as ``False``, loggers which
exist when this call is made are left
alone. The default is ``True`` because this
enables old behaviour in a backward-
compatible way. This behaviour is to
disable any existing loggers unless they or
their ancestors are explicitly named in the
logging configuration.
.. versionchanged:: 2.6
The ``disable_existing_loggers`` keyword argument was added. Previously,
existing loggers were *always* disabled.
.. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT)
......
......@@ -28,7 +28,7 @@ Windows.
.. note::
Functionality within this package requires that the ``__main__`` method be
Functionality within this package requires that the ``__main__`` module be
importable by the children. This is covered in :ref:`multiprocessing-programming`
however it is worth pointing out here. This means that some examples, such
as the :class:`multiprocessing.Pool` examples will not work in the
......
......@@ -204,6 +204,8 @@ The :mod:`signal` module defines the following functions:
attempting to call it from other threads will cause a :exc:`ValueError`
exception to be raised.
.. versionadded:: 2.6
.. function:: siginterrupt(signalnum, flag)
......
......@@ -178,9 +178,10 @@ This module defines one class called :class:`Popen`:
:attr:`stdout`, :attr:`stdin` and :attr:`stderr` are not updated by the
communicate() method.
The *startupinfo* and *creationflags*, if given, will be passed to the
underlying CreateProcess() function. They can specify things such as appearance
of the main window and priority for the new process. (Windows only)
If given, *startupinfo* will be a :class:`STARTUPINFO` object, which is
passed to the underlying ``CreateProcess`` function.
*creationflags*, if given, can be :data:`CREATE_NEW_CONSOLE` or
:data:`CREATE_NEW_PROCESS_GROUP`. (Windows only)
.. data:: PIPE
......@@ -200,7 +201,7 @@ This module defines one class called :class:`Popen`:
Convenience Functions
^^^^^^^^^^^^^^^^^^^^^
This module also defines two shortcut functions:
This module also defines the following shortcut functions:
.. function:: call(*popenargs, **kwargs)
......@@ -413,6 +414,109 @@ The following attributes are also available:
``N`` (Unix only).
Windows Popen Helpers
---------------------
The :class:`STARTUPINFO` class and following constants are only available
on Windows.
.. class:: STARTUPINFO()
Partial support of the Windows
`STARTUPINFO <http://msdn.microsoft.com/en-us/library/ms686331(v=vs.85).aspx>`__
structure is used for :class:`Popen` creation.
.. attribute:: dwFlags
A bit field that determines whether certain :class:`STARTUPINFO` members
are used when the process creates a window. ::
si = subprocess.STARTUPINFO()
si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW
.. attribute:: hStdInput
If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is
the standard input handle for the process. If :data:`STARTF_USESTDHANDLES`
is not specified, the default for standard input is the keyboard buffer.
.. attribute:: hStdOutput
If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is
the standard output handle for the process. Otherwise, this member is
ignored and the default for standard output is the console window's
buffer.
.. attribute:: hStdError
If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is
the standard error handle for the process. Otherwise, this member is
ignored and the default for standard error is the console window's buffer.
.. attribute:: wShowWindow
If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member
can be any of the values that can be specified in the ``nCmdShow``
parameter for the
`ShowWindow <http://msdn.microsoft.com/en-us/library/ms633548(v=vs.85).aspx>`__
function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is
ignored.
:data:`SW_HIDE` is provided for this attribute. It is used when
:class:`Popen` is called with ``shell=True``.
Constants
^^^^^^^^^
The :mod:`subprocess` module exposes the following constants.
.. data:: STD_INPUT_HANDLE
The standard input device. Initially, this is the console input buffer,
``CONIN$``.
.. data:: STD_OUTPUT_HANDLE
The standard output device. Initially, this is the active console screen
buffer, ``CONOUT$``.
.. data:: STD_ERROR_HANDLE
The standard error device. Initially, this is the active console screen
buffer, ``CONOUT$``.
.. data:: SW_HIDE
Hides the window. Another window will be activated.
.. data:: STARTF_USESTDHANDLES
Specifies that the :attr:`STARTUPINFO.hStdInput`,
:attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members
contain additional information.
.. data:: STARTF_USESHOWWINDOW
Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains
additional information.
.. data:: CREATE_NEW_CONSOLE
The new process has a new console, instead of inheriting its parent's
console (the default).
This flag is always set when :class:`Popen` is created with ``shell=True``.
.. data:: CREATE_NEW_PROCESS_GROUP
A :class:`Popen` ``creationflags`` parameter to specify that a new process
group will be created. This flag is necessary for using :func:`os.kill`
on the subprocess.
This flag is ignored if :data:`CREATE_NEW_CONSOLE` is specified.
.. _subprocess-replacements:
Replacing Older Functions with the subprocess Module
......
......@@ -562,6 +562,30 @@ always available.
``version_info`` value may be used for a more human-friendly encoding of the
same information.
The ``hexversion`` is a 32-bit number with the following layout
+-------------------------+------------------------------------------------+
| bits (big endian order) | meaning |
+=========================+================================================+
| :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in |
| | ``2.1.0a3``) |
+-------------------------+------------------------------------------------+
| :const:`9-16` | ``PY_MINOR_VERSION`` (the ``1`` in |
| | ``2.1.0a3``) |
+-------------------------+------------------------------------------------+
| :const:`17-24` | ``PY_MICRO_VERSION`` (the ``0`` in |
| | ``2.1.0a3``) |
+-------------------------+------------------------------------------------+
| :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, |
| | ``0xB`` for beta, ``0xC`` for gamma and |
| | ``0xF`` for final) |
+-------------------------+------------------------------------------------+
| :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in |
| | ``2.1.0a3``) |
+-------------------------+------------------------------------------------+
thus ``2.1.0a3`` is hexversion ``0x020100a3``
.. versionadded:: 1.5.2
......
......@@ -167,15 +167,15 @@ High-level interface
the download is interrupted.
The *Content-Length* is treated as a lower bound: if there's more data to read,
urlretrieve reads more data, but if less data is available, it raises the
exception.
:func:`urlretrieve` reads more data, but if less data is available, it raises
the exception.
You can still retrieve the downloaded data in this case, it is stored in the
:attr:`content` attribute of the exception instance.
If no *Content-Length* header was supplied, urlretrieve can not check the size
of the data it has downloaded, and just returns it. In this case you just have
to assume that the download was successful.
If no *Content-Length* header was supplied, :func:`urlretrieve` can not check
the size of the data it has downloaded, and just returns it. In this case you
just have to assume that the download was successful.
.. data:: _urlopener
......
......@@ -111,6 +111,7 @@ PyAPI_FUNC(void) PyThreadState_Clear(PyThreadState *);
PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *);
#ifdef WITH_THREAD
PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void);
PyAPI_FUNC(void) _PyGILState_Reinit(void);
#endif
PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void);
......
......@@ -29,17 +29,8 @@ It has the following interface (key and data are strings):
list = d.keys() # return a list of all existing keys (slow!)
Future versions may change the order in which implementations are
tested for existence, add interfaces to other dbm-like
tested for existence, and add interfaces to other dbm-like
implementations.
The open function has an optional second argument. This can be 'r',
for read-only access, 'w', for read-write access of an existing
database, 'c' for read-write access to a new or existing database, and
'n' for read-write access to a new database. The default is 'r'.
Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it
only if it doesn't exist; and 'n' always creates a new database.
"""
class error(Exception):
......@@ -63,7 +54,18 @@ if not _defaultmod:
error = tuple(_errors)
def open(file, flag = 'r', mode = 0666):
def open(file, flag='r', mode=0666):
"""Open or create database at path given by *file*.
Optional argument *flag* can be 'r' (default) for read-only access, 'w'
for read-write access of an existing database, 'c' for read-write access
to a new or existing database, and 'n' for read-write access to a new
database.
Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it
only if it doesn't exist; and 'n' always creates a new database.
"""
# guess the type of an existing database
from whichdb import whichdb
result=whichdb(file)
......
......@@ -6,37 +6,16 @@ import _abcoll
__all__ += _abcoll.__all__
from _collections import deque, defaultdict
from operator import itemgetter as _itemgetter, eq as _eq
from operator import itemgetter as _itemgetter
from keyword import iskeyword as _iskeyword
import sys as _sys
import heapq as _heapq
from itertools import repeat as _repeat, chain as _chain, starmap as _starmap, \
ifilter as _ifilter, imap as _imap
from itertools import repeat as _repeat, chain as _chain, starmap as _starmap
try:
from thread import get_ident
from thread import get_ident as _get_ident
except ImportError:
from dummy_thread import get_ident
def _recursive_repr(user_function):
'Decorator to make a repr function return "..." for a recursive call'
repr_running = set()
def wrapper(self):
key = id(self), get_ident()
if key in repr_running:
return '...'
repr_running.add(key)
try:
result = user_function(self)
finally:
repr_running.discard(key)
return result
# Can't use functools.wraps() here because of bootstrap issues
wrapper.__module__ = getattr(user_function, '__module__')
wrapper.__doc__ = getattr(user_function, '__doc__')
wrapper.__name__ = getattr(user_function, '__name__')
return wrapper
from dummy_thread import get_ident as _get_ident
################################################################################
......@@ -48,17 +27,17 @@ class OrderedDict(dict):
# An inherited dict maps keys to values.
# The inherited dict provides __getitem__, __len__, __contains__, and get.
# The remaining methods are order-aware.
# Big-O running times for all methods are the same as for regular dictionaries.
# Big-O running times for all methods are the same as regular dictionaries.
# The internal self.__map dictionary maps keys to links in a doubly linked list.
# The internal self.__map dict maps keys to links in a doubly linked list.
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# Each link is stored as a list of length three: [PREV, NEXT, KEY].
def __init__(self, *args, **kwds):
'''Initialize an ordered dictionary. Signature is the same as for
regular dictionaries, but keyword arguments are not recommended
because their insertion order is arbitrary.
'''Initialize an ordered dictionary. The signature is the same as
regular dictionaries, but keyword arguments are not recommended because
their insertion order is arbitrary.
'''
if len(args) > 1:
......@@ -66,17 +45,15 @@ class OrderedDict(dict):
try:
self.__root
except AttributeError:
self.__root = root = [None, None, None] # sentinel node
PREV = 0
NEXT = 1
root[PREV] = root[NEXT] = root
self.__root = root = [] # sentinel node
root[:] = [root, root, None]
self.__map = {}
self.__update(*args, **kwds)
def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link which goes at the end of the linked
# list, and the inherited dictionary is updated with the new key/value pair.
# Setting a new item creates a new link at the end of the linked list,
# and the inherited dictionary is updated with the new key/value pair.
if key not in self:
root = self.__root
last = root[PREV]
......@@ -85,79 +62,82 @@ class OrderedDict(dict):
def __delitem__(self, key, PREV=0, NEXT=1, dict_delitem=dict.__delitem__):
'od.__delitem__(y) <==> del od[y]'
# Deleting an existing item uses self.__map to find the link which is
# then removed by updating the links in the predecessor and successor nodes.
# Deleting an existing item uses self.__map to find the link which gets
# removed by updating the links in the predecessor and successor nodes.
dict_delitem(self, key)
link = self.__map.pop(key)
link_prev = link[PREV]
link_next = link[NEXT]
link_prev, link_next, key = self.__map.pop(key)
link_prev[NEXT] = link_next
link_next[PREV] = link_prev
def __iter__(self, NEXT=1, KEY=2):
def __iter__(self):
'od.__iter__() <==> iter(od)'
# Traverse the linked list in order.
NEXT, KEY = 1, 2
root = self.__root
curr = root[NEXT]
while curr is not root:
yield curr[KEY]
curr = curr[NEXT]
def __reversed__(self, PREV=0, KEY=2):
def __reversed__(self):
'od.__reversed__() <==> reversed(od)'
# Traverse the linked list in reverse order.
PREV, KEY = 0, 2
root = self.__root
curr = root[PREV]
while curr is not root:
yield curr[KEY]
curr = curr[PREV]
def __reduce__(self):
'Return state information for pickling'
items = [[k, self[k]] for k in self]
tmp = self.__map, self.__root
del self.__map, self.__root
inst_dict = vars(self).copy()
self.__map, self.__root = tmp
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
def clear(self):
'od.clear() -> None. Remove all items from od.'
try:
for node in self.__map.itervalues():
del node[:]
self.__root[:] = [self.__root, self.__root, None]
self.__map.clear()
except AttributeError:
pass
for node in self.__map.itervalues():
del node[:]
root = self.__root
root[:] = [root, root, None]
self.__map.clear()
dict.clear(self)
update = __update = MutableMapping.update
keys = MutableMapping.keys
values = MutableMapping.values
items = MutableMapping.items
iterkeys = MutableMapping.iterkeys
itervalues = MutableMapping.itervalues
iteritems = MutableMapping.iteritems
__ne__ = MutableMapping.__ne__
# -- the following methods do not depend on the internal structure --
def viewkeys(self):
"od.viewkeys() -> a set-like object providing a view on od's keys"
return KeysView(self)
def keys(self):
'od.keys() -> list of keys in od'
return list(self)
def viewvalues(self):
"od.viewvalues() -> an object providing a view on od's values"
return ValuesView(self)
def values(self):
'od.values() -> list of values in od'
return [self[key] for key in self]
def viewitems(self):
"od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self)
def items(self):
'od.items() -> list of (key, value) pairs in od'
return [(key, self[key]) for key in self]
def iterkeys(self):
'od.iterkeys() -> an iterator over the keys in od'
return iter(self)
def itervalues(self):
'od.itervalues -> an iterator over the values in od'
for k in self:
yield self[k]
def iteritems(self):
'od.iteritems -> an iterator over the (key, value) pairs in od'
for k in self:
yield (k, self[k])
update = MutableMapping.update
__update = update # let subclasses override update without breaking __init__
__marker = object()
def pop(self, key, default=__marker):
'''od.pop(k[,d]) -> v, remove specified key and return the corresponding
value. If key is not found, d is returned if given, otherwise KeyError
is raised.
'''
if key in self:
result = self[key]
del self[key]
......@@ -184,12 +164,28 @@ class OrderedDict(dict):
value = self.pop(key)
return key, value
@_recursive_repr
def __repr__(self):
def __repr__(self, _repr_running={}):
'od.__repr__() <==> repr(od)'
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
call_key = id(self), _get_ident()
if call_key in _repr_running:
return '...'
_repr_running[call_key] = 1
try:
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
finally:
del _repr_running[call_key]
def __reduce__(self):
'Return state information for pickling'
items = [[k, self[k]] for k in self]
inst_dict = vars(self).copy()
for k in vars(OrderedDict()):
inst_dict.pop(k, None)
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
def copy(self):
'od.copy() -> a shallow copy of od'
......@@ -197,14 +193,14 @@ class OrderedDict(dict):
@classmethod
def fromkeys(cls, iterable, value=None):
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
and values equal to v (which defaults to None).
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
If not specified, the value defaults to None.
'''
d = cls()
self = cls()
for key in iterable:
d[key] = value
return d
self[key] = value
return self
def __eq__(self, other):
'''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
......@@ -212,10 +208,27 @@ class OrderedDict(dict):
'''
if isinstance(other, OrderedDict):
return len(self)==len(other) and \
all(_imap(_eq, self.iteritems(), other.iteritems()))
return len(self)==len(other) and self.items() == other.items()
return dict.__eq__(self, other)
def __ne__(self, other):
'od.__ne__(y) <==> od!=y'
return not self == other
# -- the following methods support python 3.x style dictionary views --
def viewkeys(self):
"od.viewkeys() -> a set-like object providing a view on od's keys"
return KeysView(self)
def viewvalues(self):
"od.viewvalues() -> an object providing a view on od's values"
return ValuesView(self)
def viewitems(self):
"od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self)
################################################################################
### namedtuple
......@@ -516,8 +529,8 @@ class Counter(dict):
self.subtract(kwds)
def copy(self):
'Like dict.copy() but returns a Counter instance instead of a dict.'
return Counter(self)
'Return a shallow copy.'
return self.__class__(self)
def __reduce__(self):
return self.__class__, (dict(self),)
......@@ -552,10 +565,13 @@ class Counter(dict):
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem in set(self) | set(other):
newcount = self[elem] + other[elem]
for elem, count in self.items():
newcount = count + other[elem]
if newcount > 0:
result[elem] = newcount
for elem, count in other.items():
if elem not in self and count > 0:
result[elem] = count
return result
def __sub__(self, other):
......@@ -568,10 +584,13 @@ class Counter(dict):
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem in set(self) | set(other):
newcount = self[elem] - other[elem]
for elem, count in self.items():
newcount = count - other[elem]
if newcount > 0:
result[elem] = newcount
for elem, count in other.items():
if elem not in self and count < 0:
result[elem] = 0 - count
return result
def __or__(self, other):
......@@ -584,11 +603,14 @@ class Counter(dict):
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem in set(self) | set(other):
p, q = self[elem], other[elem]
newcount = q if p < q else p
for elem, count in self.items():
other_count = other[elem]
newcount = other_count if count < other_count else count
if newcount > 0:
result[elem] = newcount
for elem, count in other.items():
if elem not in self and count > 0:
result[elem] = count
return result
def __and__(self, other):
......@@ -601,11 +623,9 @@ class Counter(dict):
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
if len(self) < len(other):
self, other = other, self
for elem in _ifilter(self.__contains__, other):
p, q = self[elem], other[elem]
newcount = p if p < q else q
for elem, count in self.items():
other_count = other[elem]
newcount = count if count < other_count else other_count
if newcount > 0:
result[elem] = newcount
return result
......
......@@ -306,17 +306,20 @@ class sdist(Command):
rstrip_ws=1,
collapse_join=1)
while 1:
line = template.readline()
if line is None: # end of file
break
try:
self.filelist.process_template_line(line)
except DistutilsTemplateError, msg:
self.warn("%s, line %d: %s" % (template.filename,
template.current_line,
msg))
try:
while 1:
line = template.readline()
if line is None: # end of file
break
try:
self.filelist.process_template_line(line)
except DistutilsTemplateError, msg:
self.warn("%s, line %d: %s" % (template.filename,
template.current_line,
msg))
finally:
template.close()
def prune_file_list(self):
"""Prune off branches that might slip into the file list as created
......
......@@ -62,7 +62,7 @@ def unix_getpass(prompt='Password: ', stream=None):
try:
old = termios.tcgetattr(fd) # a copy to save
new = old[:]
new[3] &= ~(termios.ECHO|termios.ISIG) # 3 == 'lflags'
new[3] &= ~termios.ECHO # 3 == 'lflags'
tcsetattr_flags = termios.TCSAFLUSH
if hasattr(termios, 'TCSASOFT'):
tcsetattr_flags |= termios.TCSASOFT
......
......@@ -441,8 +441,15 @@ __all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call",
"check_output", "CalledProcessError"]
if mswindows:
from _subprocess import CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP
__all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP"])
from _subprocess import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP,
STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
STD_ERROR_HANDLE, SW_HIDE,
STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW)
__all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP",
"STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE",
"STD_ERROR_HANDLE", "SW_HIDE",
"STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"])
try:
MAXFD = os.sysconf("SC_OPEN_MAX")
except:
......
......@@ -2239,6 +2239,8 @@ class TarFile(object):
if hasattr(os, "symlink") and hasattr(os, "link"):
# For systems that support symbolic and hard links.
if tarinfo.issym():
if os.path.exists(targetpath):
os.unlink(targetpath)
os.symlink(tarinfo.linkname, targetpath)
else:
# See extract().
......
......@@ -1177,6 +1177,63 @@ class MixinStrUnicodeUserStringTest:
# mixed use of str and unicode
self.assertEqual('a/b/c'.rpartition(u'/'), ('a/b', '/', 'c'))
def test_none_arguments(self):
# issue 11828
s = 'hello'
self.checkequal(2, s, 'find', 'l', None)
self.checkequal(3, s, 'find', 'l', -2, None)
self.checkequal(2, s, 'find', 'l', None, -2)
self.checkequal(0, s, 'find', 'h', None, None)
self.checkequal(3, s, 'rfind', 'l', None)
self.checkequal(3, s, 'rfind', 'l', -2, None)
self.checkequal(2, s, 'rfind', 'l', None, -2)
self.checkequal(0, s, 'rfind', 'h', None, None)
self.checkequal(2, s, 'index', 'l', None)
self.checkequal(3, s, 'index', 'l', -2, None)
self.checkequal(2, s, 'index', 'l', None, -2)
self.checkequal(0, s, 'index', 'h', None, None)
self.checkequal(3, s, 'rindex', 'l', None)
self.checkequal(3, s, 'rindex', 'l', -2, None)
self.checkequal(2, s, 'rindex', 'l', None, -2)
self.checkequal(0, s, 'rindex', 'h', None, None)
self.checkequal(2, s, 'count', 'l', None)
self.checkequal(1, s, 'count', 'l', -2, None)
self.checkequal(1, s, 'count', 'l', None, -2)
self.checkequal(0, s, 'count', 'x', None, None)
self.checkequal(True, s, 'endswith', 'o', None)
self.checkequal(True, s, 'endswith', 'lo', -2, None)
self.checkequal(True, s, 'endswith', 'l', None, -2)
self.checkequal(False, s, 'endswith', 'x', None, None)
self.checkequal(True, s, 'startswith', 'h', None)
self.checkequal(True, s, 'startswith', 'l', -2, None)
self.checkequal(True, s, 'startswith', 'h', None, -2)
self.checkequal(False, s, 'startswith', 'x', None, None)
def test_find_etc_raise_correct_error_messages(self):
# issue 11828
s = 'hello'
x = 'x'
self.assertRaisesRegexp(TypeError, r'\bfind\b', s.find,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\brfind\b', s.rfind,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\bindex\b', s.index,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\brindex\b', s.rindex,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'^count\(', s.count,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith,
x, None, None, None)
class MixinStrStringUserStringTest:
# Additional tests for 8bit strings, i.e. str, UserString and
# the string module
......
......@@ -456,6 +456,68 @@ class BaseBytesTest(unittest.TestCase):
self.assertEqual([ord(b[i:i+1]) for i in range(len(b))],
[0, 65, 127, 128, 255])
def test_none_arguments(self):
# issue 11828
b = self.type2test(b'hello')
l = self.type2test(b'l')
h = self.type2test(b'h')
x = self.type2test(b'x')
o = self.type2test(b'o')
self.assertEqual(2, b.find(l, None))
self.assertEqual(3, b.find(l, -2, None))
self.assertEqual(2, b.find(l, None, -2))
self.assertEqual(0, b.find(h, None, None))
self.assertEqual(3, b.rfind(l, None))
self.assertEqual(3, b.rfind(l, -2, None))
self.assertEqual(2, b.rfind(l, None, -2))
self.assertEqual(0, b.rfind(h, None, None))
self.assertEqual(2, b.index(l, None))
self.assertEqual(3, b.index(l, -2, None))
self.assertEqual(2, b.index(l, None, -2))
self.assertEqual(0, b.index(h, None, None))
self.assertEqual(3, b.rindex(l, None))
self.assertEqual(3, b.rindex(l, -2, None))
self.assertEqual(2, b.rindex(l, None, -2))
self.assertEqual(0, b.rindex(h, None, None))
self.assertEqual(2, b.count(l, None))
self.assertEqual(1, b.count(l, -2, None))
self.assertEqual(1, b.count(l, None, -2))
self.assertEqual(0, b.count(x, None, None))
self.assertEqual(True, b.endswith(o, None))
self.assertEqual(True, b.endswith(o, -2, None))
self.assertEqual(True, b.endswith(l, None, -2))
self.assertEqual(False, b.endswith(x, None, None))
self.assertEqual(True, b.startswith(h, None))
self.assertEqual(True, b.startswith(l, -2, None))
self.assertEqual(True, b.startswith(h, None, -2))
self.assertEqual(False, b.startswith(x, None, None))
def test_find_etc_raise_correct_error_messages(self):
# issue 11828
b = self.type2test(b'hello')
x = self.type2test(b'x')
self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith,
x, None, None, None)
self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith,
x, None, None, None)
class ByteArrayTest(BaseBytesTest):
type2test = bytearray
......
......@@ -689,6 +689,15 @@ class TestCounter(unittest.TestCase):
self.assertEqual(len(dup), len(words))
self.assertEqual(type(dup), type(words))
def test_copy_subclass(self):
class MyCounter(Counter):
pass
c = MyCounter('slartibartfast')
d = c.copy()
self.assertEqual(d, c)
self.assertEqual(len(d), len(c))
self.assertEqual(type(d), type(c))
def test_conversions(self):
# Convert to: set, list, dict
s = 'she sells sea shells by the sea shore'
......
......@@ -6,6 +6,7 @@ import subprocess
import re
import pydoc
import inspect
import keyword
import unittest
import xml.etree
import test.test_support
......@@ -351,9 +352,16 @@ class TestDescriptions(unittest.TestCase):
self.assertIn('_asdict', helptext)
class TestHelper(unittest.TestCase):
def test_keywords(self):
self.assertEqual(sorted(pydoc.Helper.keywords),
sorted(keyword.kwlist))
def test_main():
test.test_support.run_unittest(PyDocDocTest,
TestDescriptions)
TestDescriptions,
TestHelper)
if __name__ == "__main__":
test_main()
......@@ -11,6 +11,7 @@ import unittest
from test import test_support
import os
from os import path
from time import sleep
startfile = test_support.get_attribute(os, 'startfile')
......@@ -26,11 +27,16 @@ class TestCase(unittest.TestCase):
empty = path.join(path.dirname(__file__), "empty.vbs")
startfile(empty)
startfile(empty, "open")
# Give the child process some time to exit before we finish.
# Otherwise the cleanup code will not be able to delete the cwd,
# because it is still in use.
sleep(0.1)
def test_empty_u(self):
empty = path.join(path.dirname(__file__), "empty.vbs")
startfile(unicode(empty, "mbcs"))
startfile(unicode(empty, "mbcs"), "open")
sleep(0.1)
def test_main():
test_support.run_unittest(TestCase)
......
......@@ -414,7 +414,18 @@ class StrTest(
self.assertEqual('Andr\202 x'.decode('ascii', 'replace'),
'Andr\202 x'.decode(encoding='ascii', errors='replace'))
def test_startswith_endswith_errors(self):
with self.assertRaises(UnicodeDecodeError):
'\xff'.startswith(u'x')
with self.assertRaises(UnicodeDecodeError):
'\xff'.endswith(u'x')
for meth in ('foo'.startswith, 'foo'.endswith):
with self.assertRaises(TypeError) as cm:
meth(['f'])
exc = str(cm.exception)
self.assertIn('unicode', exc)
self.assertIn('str', exc)
self.assertIn('tuple', exc)
def test_main():
test_support.run_unittest(StrTest)
......
......@@ -843,6 +843,34 @@ class WriteTest(WriteTestBase):
finally:
os.chdir(cwd)
@unittest.skipUnless(hasattr(os, 'symlink'), "needs os.symlink")
def test_extractall_symlinks(self):
# Test if extractall works properly when tarfile contains symlinks
tempdir = os.path.join(TEMPDIR, "testsymlinks")
temparchive = os.path.join(TEMPDIR, "testsymlinks.tar")
os.mkdir(tempdir)
try:
source_file = os.path.join(tempdir,'source')
target_file = os.path.join(tempdir,'symlink')
with open(source_file,'w') as f:
f.write('something\n')
os.symlink(source_file, target_file)
tar = tarfile.open(temparchive,'w')
tar.add(source_file, arcname=os.path.basename(source_file))
tar.add(target_file, arcname=os.path.basename(target_file))
tar.close()
# Let's extract it to the location which contains the symlink
tar = tarfile.open(temparchive,'r')
# this should not raise OSError: [Errno 17] File exists
try:
tar.extractall(path=tempdir)
except OSError:
self.fail("extractall failed with symlinked files")
finally:
tar.close()
finally:
os.unlink(temparchive)
shutil.rmtree(tempdir)
class StreamWriteTest(WriteTestBase):
......
......@@ -442,6 +442,17 @@ class UnicodeTest(
return u'\u1234'
self.assertEqual('%s' % Wrapper(), u'\u1234')
def test_startswith_endswith_errors(self):
for meth in (u'foo'.startswith, u'foo'.endswith):
with self.assertRaises(UnicodeDecodeError):
meth('\xff')
with self.assertRaises(TypeError) as cm:
meth(['f'])
exc = str(cm.exception)
self.assertIn('unicode', exc)
self.assertIn('str', exc)
self.assertIn('tuple', exc)
@test_support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR')
def test_format_float(self):
# should not format with a comma, but always with C locale
......
......@@ -115,20 +115,20 @@ class TestsWithSourceFile(unittest.TestCase):
# Read the ZIP archive
with zipfile.ZipFile(f, "r", compression) as zipfp:
zipdata1 = []
zipopen1 = zipfp.open(TESTFN)
while True:
read_data = zipopen1.read(256)
if not read_data:
break
zipdata1.append(read_data)
with zipfp.open(TESTFN) as zipopen1:
while True:
read_data = zipopen1.read(256)
if not read_data:
break
zipdata1.append(read_data)
zipdata2 = []
zipopen2 = zipfp.open("another.name")
while True:
read_data = zipopen2.read(256)
if not read_data:
break
zipdata2.append(read_data)
with zipfp.open("another.name") as zipopen2:
while True:
read_data = zipopen2.read(256)
if not read_data:
break
zipdata2.append(read_data)
self.assertEqual(''.join(zipdata1), self.data)
self.assertEqual(''.join(zipdata2), self.data)
......@@ -147,7 +147,8 @@ class TestsWithSourceFile(unittest.TestCase):
infos = zipfp.infolist()
data = ""
for info in infos:
data += zipfp.open(info).read()
with zipfp.open(info) as f:
data += f.read()
self.assertTrue(data == "foobar" or data == "barfoo")
data = ""
for info in infos:
......@@ -160,12 +161,12 @@ class TestsWithSourceFile(unittest.TestCase):
# Read the ZIP archive
with zipfile.ZipFile(f, "r", compression) as zipfp:
zipdata1 = []
zipopen1 = zipfp.open(TESTFN)
while True:
read_data = zipopen1.read(randint(1, 1024))
if not read_data:
break
zipdata1.append(read_data)
with zipfp.open(TESTFN) as zipopen1:
while True:
read_data = zipopen1.read(randint(1, 1024))
if not read_data:
break
zipdata1.append(read_data)
self.assertEqual(''.join(zipdata1), self.data)
......@@ -177,16 +178,14 @@ class TestsWithSourceFile(unittest.TestCase):
f = StringIO()
data = 'a\r\n' * 16 * 1024
zipfp = zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED)
zipfp.writestr(TESTFN, data)
zipfp.close()
with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as zipfp:
zipfp.writestr(TESTFN, data)
data2 = ''
zipfp = zipfile.ZipFile(f, 'r')
zipopen = zipfp.open(TESTFN, 'rU')
for line in zipopen:
data2 += line
zipfp.close()
with zipfile.ZipFile(f, 'r') as zipfp:
with zipfp.open(TESTFN, 'rU') as zipopen:
for line in zipopen:
data2 += line
self.assertEqual(data, data2.replace('\n', '\r\n'))
......@@ -194,42 +193,41 @@ class TestsWithSourceFile(unittest.TestCase):
self.make_test_archive(f, compression)
# Read the ZIP archive
zipfp = zipfile.ZipFile(f, "r")
zipopen = zipfp.open(TESTFN)
data = ''
while True:
read = zipopen.readline()
if not read:
break
data += read
read = zipopen.read(100)
if not read:
break
data += read
with zipfile.ZipFile(f, "r") as zipfp:
with zipfp.open(TESTFN) as zipopen:
data = ''
while True:
read = zipopen.readline()
if not read:
break
data += read
read = zipopen.read(100)
if not read:
break
data += read
self.assertEqual(data, self.data)
zipfp.close()
def zip_readline_test(self, f, compression):
self.make_test_archive(f, compression)
# Read the ZIP archive
with zipfile.ZipFile(f, "r") as zipfp:
zipopen = zipfp.open(TESTFN)
for line in self.line_gen:
linedata = zipopen.readline()
self.assertEqual(linedata, line + '\n')
with zipfp.open(TESTFN) as zipopen:
for line in self.line_gen:
linedata = zipopen.readline()
self.assertEqual(linedata, line + '\n')
def zip_readlines_test(self, f, compression):
self.make_test_archive(f, compression)
# Read the ZIP archive
with zipfile.ZipFile(f, "r") as zipfp:
ziplines = zipfp.open(TESTFN).readlines()
for line, zipline in zip(self.line_gen, ziplines):
self.assertEqual(zipline, line + '\n')
with zipfp.open(TESTFN) as zo:
ziplines = zo.readlines()
for line, zipline in zip(self.line_gen, ziplines):
self.assertEqual(zipline, line + '\n')
def zip_iterlines_test(self, f, compression):
self.make_test_archive(f, compression)
......@@ -301,9 +299,9 @@ class TestsWithSourceFile(unittest.TestCase):
# Get an open object for strfile
with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp:
openobj = zipfp.open("strfile")
self.assertEqual(openobj.read(1), '1')
self.assertEqual(openobj.read(1), '2')
with zipfp.open("strfile") as openobj:
self.assertEqual(openobj.read(1), '1')
self.assertEqual(openobj.read(1), '2')
def test_absolute_arcnames(self):
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
......@@ -775,8 +773,8 @@ class OtherTests(unittest.TestCase):
self.assertRaises(IOError, zipfile.ZipFile, TESTFN)
def test_empty_file_raises_BadZipFile(self):
f = open(TESTFN, 'w')
f.close()
with open(TESTFN, 'w') as f:
pass
self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN)
with open(TESTFN, 'w') as fp:
......@@ -820,11 +818,11 @@ class OtherTests(unittest.TestCase):
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
# read the data to make sure the file is there
f = zipf.open("foo.txt")
for i in xrange(FIXEDTEST_SIZE):
self.assertEqual(f.read(0), '')
with zipf.open("foo.txt") as f:
for i in xrange(FIXEDTEST_SIZE):
self.assertEqual(f.read(0), '')
self.assertEqual(f.read(), "O, for a Muse of Fire!")
self.assertEqual(f.read(), "O, for a Muse of Fire!")
def test_open_non_existent_item(self):
"""Check that attempting to call open() for an item that doesn't
......@@ -952,15 +950,15 @@ class OtherTests(unittest.TestCase):
def test_empty_zipfile(self):
# Check that creating a file in 'w' or 'a' mode and closing without
# adding any files to the archives creates a valid empty ZIP file
zipf = zipfile.ZipFile(TESTFN, mode="w")
zipf.close()
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
pass
try:
zipf = zipfile.ZipFile(TESTFN, mode="r")
except zipfile.BadZipfile:
self.fail("Unable to create empty ZIP file in 'w' mode")
zipf = zipfile.ZipFile(TESTFN, mode="a")
zipf.close()
with zipfile.ZipFile(TESTFN, mode="a") as zipf:
pass
try:
zipf = zipfile.ZipFile(TESTFN, mode="r")
except:
......@@ -970,8 +968,8 @@ class OtherTests(unittest.TestCase):
# Issue 1710703: Check that opening a file with less than 22 bytes
# raises a BadZipfile exception (rather than the previously unhelpful
# IOError)
f = open(TESTFN, 'w')
f.close()
with open(TESTFN, 'w') as f:
pass
self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN, 'r')
def tearDown(self):
......@@ -1084,20 +1082,20 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
# Read the ZIP archive
with zipfile.ZipFile(f, "r", compression) as zipfp:
zipdata1 = []
zipopen1 = zipfp.open(TESTFN)
while True:
read_data = zipopen1.read(256)
if not read_data:
break
zipdata1.append(read_data)
with zipfp.open(TESTFN) as zipopen1:
while True:
read_data = zipopen1.read(256)
if not read_data:
break
zipdata1.append(read_data)
zipdata2 = []
zipopen2 = zipfp.open("another.name")
while True:
read_data = zipopen2.read(256)
if not read_data:
break
zipdata2.append(read_data)
with zipfp.open("another.name") as zipopen2:
while True:
read_data = zipopen2.read(256)
if not read_data:
break
zipdata2.append(read_data)
testdata1 = ''.join(zipdata1)
self.assertEqual(len(testdata1), len(self.data))
......@@ -1122,12 +1120,12 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
# Read the ZIP archive
with zipfile.ZipFile(f, "r", compression) as zipfp:
zipdata1 = []
zipopen1 = zipfp.open(TESTFN)
while True:
read_data = zipopen1.read(randint(1, 1024))
if not read_data:
break
zipdata1.append(read_data)
with zipfp.open(TESTFN) as zipopen1:
while True:
read_data = zipopen1.read(randint(1, 1024))
if not read_data:
break
zipdata1.append(read_data)
testdata = ''.join(zipdata1)
self.assertEqual(len(testdata), len(self.data))
......@@ -1167,12 +1165,11 @@ class TestsWithMultipleOpens(unittest.TestCase):
# Verify that (when the ZipFile is in control of creating file objects)
# multiple open() calls can be made without interfering with each other.
with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
zopen1 = zipf.open('ones')
zopen2 = zipf.open('twos')
data1 = zopen1.read(500)
data2 = zopen2.read(500)
data1 += zopen1.read(500)
data2 += zopen2.read(500)
with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
data1 = zopen1.read(500)
data2 = zopen2.read(500)
data1 += zopen1.read(500)
data2 += zopen2.read(500)
self.assertEqual(data1, '1'*FIXEDTEST_SIZE)
self.assertEqual(data2, '2'*FIXEDTEST_SIZE)
......@@ -1180,12 +1177,11 @@ class TestsWithMultipleOpens(unittest.TestCase):
# Verify that (when the ZipFile is in control of creating file objects)
# multiple open() calls can be made without interfering with each other.
with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
zopen1 = zipf.open('ones')
data1 = zopen1.read(500)
zopen2 = zipf.open('twos')
data2 = zopen2.read(500)
data1 += zopen1.read(500)
data2 += zopen2.read(500)
with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
data1 = zopen1.read(500)
data2 = zopen2.read(500)
data1 += zopen1.read(500)
data2 += zopen2.read(500)
self.assertEqual(data1, '1'*FIXEDTEST_SIZE)
self.assertEqual(data2, '2'*FIXEDTEST_SIZE)
......@@ -1244,7 +1240,8 @@ class UniversalNewlineTests(unittest.TestCase):
# Read the ZIP archive
with zipfile.ZipFile(f, "r") as zipfp:
for sep, fn in self.arcfiles.items():
zipdata = zipfp.open(fn, "rU").read()
with zipfp.open(fn, "rU") as fp:
zipdata = fp.read()
self.assertEqual(self.arcdata[sep], zipdata)
def readline_read_test(self, f, compression):
......@@ -1253,18 +1250,18 @@ class UniversalNewlineTests(unittest.TestCase):
# Read the ZIP archive
zipfp = zipfile.ZipFile(f, "r")
for sep, fn in self.arcfiles.items():
zipopen = zipfp.open(fn, "rU")
data = ''
while True:
read = zipopen.readline()
if not read:
break
data += read
read = zipopen.read(5)
if not read:
break
data += read
with zipfp.open(fn, "rU") as zipopen:
data = ''
while True:
read = zipopen.readline()
if not read:
break
data += read
read = zipopen.read(5)
if not read:
break
data += read
self.assertEqual(data, self.arcdata['\n'])
......@@ -1276,10 +1273,10 @@ class UniversalNewlineTests(unittest.TestCase):
# Read the ZIP archive
with zipfile.ZipFile(f, "r") as zipfp:
for sep, fn in self.arcfiles.items():
zipopen = zipfp.open(fn, "rU")
for line in self.line_gen:
linedata = zipopen.readline()
self.assertEqual(linedata, line + '\n')
with zipfp.open(fn, "rU") as zipopen:
for line in self.line_gen:
linedata = zipopen.readline()
self.assertEqual(linedata, line + '\n')
def readlines_test(self, f, compression):
self.make_test_archive(f, compression)
......@@ -1287,7 +1284,8 @@ class UniversalNewlineTests(unittest.TestCase):
# Read the ZIP archive
with zipfile.ZipFile(f, "r") as zipfp:
for sep, fn in self.arcfiles.items():
ziplines = zipfp.open(fn, "rU").readlines()
with zipfp.open(fn, "rU") as fp:
ziplines = fp.readlines()
for line, zipline in zip(self.line_gen, ziplines):
self.assertEqual(zipline, line + '\n')
......
......@@ -169,6 +169,10 @@ class TestCase(object):
maxDiff = 80*8
# If a string is longer than _diffThreshold, use normal comparison instead
# of difflib. See #11763.
_diffThreshold = 2**16
# Attribute used by TestSuite for classSetUp
_classSetupFailed = False
......@@ -900,6 +904,10 @@ class TestCase(object):
'Second argument is not a string')
if first != second:
# don't use difflib if the strings are too long
if (len(first) > self._diffThreshold or
len(second) > self._diffThreshold):
self._baseAssertEqual(first, second, msg)
firstlines = first.splitlines(True)
secondlines = second.splitlines(True)
if len(firstlines) == 1 and first.strip('\r\n') == first:
......
......@@ -667,6 +667,42 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
else:
self.fail('assertMultiLineEqual did not fail')
def testAssertEqual_diffThreshold(self):
# check threshold value
self.assertEqual(self._diffThreshold, 2**16)
# disable madDiff to get diff markers
self.maxDiff = None
# set a lower threshold value and add a cleanup to restore it
old_threshold = self._diffThreshold
self._diffThreshold = 2**8
self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold))
# under the threshold: diff marker (^) in error message
s = u'x' * (2**7)
with self.assertRaises(self.failureException) as cm:
self.assertEqual(s + 'a', s + 'b')
self.assertIn('^', str(cm.exception))
self.assertEqual(s + 'a', s + 'a')
# over the threshold: diff not used and marker (^) not in error message
s = u'x' * (2**9)
# if the path that uses difflib is taken, _truncateMessage will be
# called -- replace it with explodingTruncation to verify that this
# doesn't happen
def explodingTruncation(message, diff):
raise SystemError('this should not be raised')
old_truncate = self._truncateMessage
self._truncateMessage = explodingTruncation
self.addCleanup(lambda: setattr(self, '_truncateMessage', old_truncate))
s1, s2 = s + 'a', s + 'b'
with self.assertRaises(self.failureException) as cm:
self.assertEqual(s1, s2)
self.assertNotIn('^', str(cm.exception))
self.assertEqual(str(cm.exception), '%r != %r' % (s1, s2))
self.assertEqual(s + 'a', s + 'a')
def testAssertItemsEqual(self):
a = object()
self.assertItemsEqual([1, 2, 3], [3, 2, 1])
......
......@@ -60,6 +60,7 @@ Donald Beaudry
David Beazley
Robin Becker
Neal Becker
Torsten Becker
Bill Bedford
Reimer Behrends
Ben Bell
......@@ -410,6 +411,7 @@ Irmen de Jong
Lucas de Jonge
John Jorgensen
Jens B. Jorgensen
Sijin Joseph
Andreas Jung
Tattoo Mabonzo K.
Bob Kahn
......@@ -794,6 +796,7 @@ Steven Taschuk
Monty Taylor
Amy Taylor
Anatoly Techtonik
Mikhail Terekhov
Tobias Thelen
James Thomas
Robin Thomas
......
......@@ -9,6 +9,13 @@ What's New in Python 2.7.2?
Core and Builtins
-----------------
- Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_*
APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch
by Charles-François Natali.
- Issue #6780: fix starts/endswith error message to mention that tuples are
accepted too.
- Issue #5057: fix a bug in the peepholer that led to non-portable pyc files
between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP
chars (e.g. u"\U00012345"[0]).
......@@ -43,6 +50,9 @@ Core and Builtins
rather than the Py_IsInitialized flag, avoiding a Fatal Python
error in certain circumstances when an import is done in __del__.
- issue #11828: startswith and endswith don't accept None as slice index.
Patch by Torsten Becker.
- Issue #10674: Remove unused 'dictmaker' rule from grammar.
- Issue #10596: Fix float.__mod__ to have the same behaviour as
......@@ -55,9 +65,29 @@ Core and Builtins
Library
-------
- Issue #10761: Fix tarfile.extractall failure when symlinked files are
present. Initial patch by Scott Leerssen.
- Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the
strings are too long.
- Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal.
- Issue #11768: The signal handler of the signal module only calls
Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or
parallel calls. PyErr_SetInterrupt() writes also into the wake up file.
- Issue #11875: collections.OrderedDict's __reduce__ was temporarily
mutating the object instead of just working on a copy.
- Issue #11442: Add a charset parameter to the Content-type in SimpleHTTPServer
to avoid XSS attacks.
- Issue #11467: Fix urlparse behavior when handling urls which contains scheme
specific part only digits. Patch by Santoso Wijaya.
- collections.Counter().copy() now works correctly for subclasses.
- Issue #11474: Fix the bug with url2pathname() handling of '/C|/' on Windows.
Patch by Santoso Wijaya.
......@@ -358,6 +388,8 @@ IDLE
Tests
-----
- Fix test_startfile to wait for child process to terminate before finishing.
- Issue #11719: Fix message about unexpected test_msilib skip on non-Windows
platforms. Patch by Nadeem Vawda.
......
......@@ -166,6 +166,20 @@ checksignals_witharg(void * unused)
return PyErr_CheckSignals();
}
static void
trip_signal(int sig_num)
{
Handlers[sig_num].tripped = 1;
if (is_tripped)
return;
/* Set is_tripped after setting .tripped, as it gets
cleared in PyErr_CheckSignals() before .tripped. */
is_tripped = 1;
Py_AddPendingCall(checksignals_witharg, NULL);
if (wakeup_fd != -1)
write(wakeup_fd, "\0", 1);
}
static void
signal_handler(int sig_num)
{
......@@ -183,13 +197,7 @@ signal_handler(int sig_num)
if (getpid() == main_pid)
#endif
{
Handlers[sig_num].tripped = 1;
/* Set is_tripped after setting .tripped, as it gets
cleared in PyErr_CheckSignals() before .tripped. */
is_tripped = 1;
Py_AddPendingCall(checksignals_witharg, NULL);
if (wakeup_fd != -1)
write(wakeup_fd, "\0", 1);
trip_signal(sig_num);
}
#ifndef HAVE_SIGACTION
......@@ -934,9 +942,7 @@ PyErr_CheckSignals(void)
void
PyErr_SetInterrupt(void)
{
is_tripped = 1;
Handlers[SIGINT].tripped = 1;
Py_AddPendingCall((int (*)(void *))PyErr_CheckSignals, NULL);
trip_signal(SIGINT);
}
void
......@@ -970,6 +976,7 @@ void
PyOS_AfterFork(void)
{
#ifdef WITH_THREAD
_PyGILState_Reinit();
PyEval_ReInitThreads();
main_thread = PyThread_get_thread_ident();
main_pid = getpid();
......
......@@ -1149,8 +1149,8 @@ bytearray_find_internal(PyByteArrayObject *self, PyObject *args, int dir)
Py_ssize_t start=0, end=PY_SSIZE_T_MAX;
Py_ssize_t res;
if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", &subobj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("find/rfind/index/rindex",
args, &subobj, &start, &end))
return -2;
if (_getbuffer(subobj, &subbuf) < 0)
return -2;
......@@ -1200,8 +1200,7 @@ bytearray_count(PyByteArrayObject *self, PyObject *args)
Py_buffer vsub;
PyObject *count_obj;
if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end))
return NULL;
if (_getbuffer(sub_obj, &vsub) < 0)
......@@ -1359,8 +1358,7 @@ bytearray_startswith(PyByteArrayObject *self, PyObject *args)
PyObject *subobj;
int result;
if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
......@@ -1399,8 +1397,7 @@ bytearray_endswith(PyByteArrayObject *self, PyObject *args)
PyObject *subobj;
int result;
if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
......
......@@ -93,32 +93,33 @@ stringlib_contains_obj(PyObject* str, PyObject* sub)
#endif /* STRINGLIB_WANT_CONTAINS_OBJ */
#if STRINGLIB_IS_UNICODE
/*
This function is a helper for the "find" family (find, rfind, index,
rindex) of unicodeobject.c file, because they all have the same
behaviour for the arguments.
rindex) and for count, startswith and endswith, because they all have
the same behaviour for the arguments.
It does not touch the variables received until it knows everything
is ok.
Note that we receive a pointer to the pointer of the substring object,
so when we create that object in this function we don't DECREF it,
because it continues living in the caller functions (those functions,
after finishing using the substring, must DECREF it).
*/
#define FORMAT_BUFFER_SIZE 50
Py_LOCAL_INLINE(int)
_ParseTupleFinds (PyObject *args, PyObject **substring,
Py_ssize_t *start, Py_ssize_t *end) {
PyObject *tmp_substring;
stringlib_parse_args_finds(const char * function_name, PyObject *args,
PyObject **subobj,
Py_ssize_t *start, Py_ssize_t *end)
{
PyObject *tmp_subobj;
Py_ssize_t tmp_start = 0;
Py_ssize_t tmp_end = PY_SSIZE_T_MAX;
PyObject *obj_start=Py_None, *obj_end=Py_None;
char format[FORMAT_BUFFER_SIZE] = "O|OO:";
size_t len = strlen(format);
if (!PyArg_ParseTuple(args, "O|OO:find", &tmp_substring,
&obj_start, &obj_end))
strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1);
format[FORMAT_BUFFER_SIZE - 1] = '\0';
if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end))
return 0;
/* To support None in "start" and "end" arguments, meaning
......@@ -131,16 +132,44 @@ _ParseTupleFinds (PyObject *args, PyObject **substring,
if (!_PyEval_SliceIndex(obj_end, &tmp_end))
return 0;
tmp_substring = PyUnicode_FromObject(tmp_substring);
if (!tmp_substring)
return 0;
*start = tmp_start;
*end = tmp_end;
*substring = tmp_substring;
*subobj = tmp_subobj;
return 1;
}
#undef FORMAT_BUFFER_SIZE
#if STRINGLIB_IS_UNICODE
/*
Wraps stringlib_parse_args_finds() and additionally ensures that the
first argument is a unicode object.
Note that we receive a pointer to the pointer of the substring object,
so when we create that object in this function we don't DECREF it,
because it continues living in the caller functions (those functions,
after finishing using the substring, must DECREF it).
*/
Py_LOCAL_INLINE(int)
stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args,
PyUnicodeObject **substring,
Py_ssize_t *start, Py_ssize_t *end)
{
PyObject *tmp_substring;
if(stringlib_parse_args_finds(function_name, args, &tmp_substring,
start, end)) {
tmp_substring = PyUnicode_FromObject(tmp_substring);
if (!tmp_substring)
return 0;
*substring = (PyUnicodeObject *)tmp_substring;
return 1;
}
return 0;
}
#endif /* STRINGLIB_IS_UNICODE */
#endif /* STRINGLIB_FIND_H */
......@@ -1693,19 +1693,9 @@ string_find_internal(PyStringObject *self, PyObject *args, int dir)
const char *sub;
Py_ssize_t sub_len;
Py_ssize_t start=0, end=PY_SSIZE_T_MAX;
PyObject *obj_start=Py_None, *obj_end=Py_None;
if (!PyArg_ParseTuple(args, "O|OO:find/rfind/index/rindex", &subobj,
&obj_start, &obj_end))
return -2;
/* To support None in "start" and "end" arguments, meaning
the same as if they were not passed.
*/
if (obj_start != Py_None)
if (!_PyEval_SliceIndex(obj_start, &start))
return -2;
if (obj_end != Py_None)
if (!_PyEval_SliceIndex(obj_end, &end))
if (!stringlib_parse_args_finds("find/rfind/index/rindex",
args, &subobj, &start, &end))
return -2;
if (PyString_Check(subobj)) {
......@@ -2117,8 +2107,7 @@ string_count(PyStringObject *self, PyObject *args)
Py_ssize_t sub_len;
Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end))
return NULL;
if (PyString_Check(sub_obj)) {
......@@ -2912,8 +2901,7 @@ string_startswith(PyStringObject *self, PyObject *args)
PyObject *subobj;
int result;
if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
......@@ -2930,8 +2918,12 @@ string_startswith(PyStringObject *self, PyObject *args)
Py_RETURN_FALSE;
}
result = _string_tailmatch(self, subobj, start, end, -1);
if (result == -1)
if (result == -1) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_Format(PyExc_TypeError, "startswith first arg must be str, "
"unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name);
return NULL;
}
else
return PyBool_FromLong(result);
}
......@@ -2953,8 +2945,7 @@ string_endswith(PyStringObject *self, PyObject *args)
PyObject *subobj;
int result;
if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
......@@ -2971,8 +2962,12 @@ string_endswith(PyStringObject *self, PyObject *args)
Py_RETURN_FALSE;
}
result = _string_tailmatch(self, subobj, start, end, +1);
if (result == -1)
if (result == -1) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_Format(PyExc_TypeError, "endswith first arg must be str, "
"unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name);
return NULL;
}
else
return PyBool_FromLong(result);
}
......
......@@ -6308,13 +6308,8 @@ unicode_count(PyUnicodeObject *self, PyObject *args)
Py_ssize_t end = PY_SSIZE_T_MAX;
PyObject *result;
if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
return NULL;
substring = (PyUnicodeObject *)PyUnicode_FromObject(
(PyObject *)substring);
if (substring == NULL)
if (!stringlib_parse_args_finds_unicode("count", args, &substring,
&start, &end))
return NULL;
ADJUST_INDICES(start, end, self->length);
......@@ -6504,12 +6499,13 @@ Return -1 on failure.");
static PyObject *
unicode_find(PyUnicodeObject *self, PyObject *args)
{
PyObject *substring;
PyUnicodeObject *substring;
Py_ssize_t start;
Py_ssize_t end;
Py_ssize_t result;
if (!_ParseTupleFinds(args, &substring, &start, &end))
if (!stringlib_parse_args_finds_unicode("find", args, &substring,
&start, &end))
return NULL;
result = stringlib_find_slice(
......@@ -6570,11 +6566,12 @@ static PyObject *
unicode_index(PyUnicodeObject *self, PyObject *args)
{
Py_ssize_t result;
PyObject *substring;
PyUnicodeObject *substring;
Py_ssize_t start;
Py_ssize_t end;
if (!_ParseTupleFinds(args, &substring, &start, &end))
if (!stringlib_parse_args_finds_unicode("index", args, &substring,
&start, &end))
return NULL;
result = stringlib_find_slice(
......@@ -7237,12 +7234,13 @@ Return -1 on failure.");
static PyObject *
unicode_rfind(PyUnicodeObject *self, PyObject *args)
{
PyObject *substring;
PyUnicodeObject *substring;
Py_ssize_t start;
Py_ssize_t end;
Py_ssize_t result;
if (!_ParseTupleFinds(args, &substring, &start, &end))
if (!stringlib_parse_args_finds_unicode("rfind", args, &substring,
&start, &end))
return NULL;
result = stringlib_rfind_slice(
......@@ -7264,12 +7262,13 @@ Like S.rfind() but raise ValueError when the substring is not found.");
static PyObject *
unicode_rindex(PyUnicodeObject *self, PyObject *args)
{
PyObject *substring;
PyUnicodeObject *substring;
Py_ssize_t start;
Py_ssize_t end;
Py_ssize_t result;
if (!_ParseTupleFinds(args, &substring, &start, &end))
if (!stringlib_parse_args_finds_unicode("rindex", args, &substring,
&start, &end))
return NULL;
result = stringlib_rfind_slice(
......@@ -7648,8 +7647,7 @@ unicode_startswith(PyUnicodeObject *self,
Py_ssize_t end = PY_SSIZE_T_MAX;
int result;
if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
......@@ -7668,8 +7666,12 @@ unicode_startswith(PyUnicodeObject *self,
Py_RETURN_FALSE;
}
substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj);
if (substring == NULL)
if (substring == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_Format(PyExc_TypeError, "startswith first arg must be str, "
"unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name);
return NULL;
}
result = tailmatch(self, substring, start, end, -1);
Py_DECREF(substring);
return PyBool_FromLong(result);
......@@ -7694,8 +7696,7 @@ unicode_endswith(PyUnicodeObject *self,
Py_ssize_t end = PY_SSIZE_T_MAX;
int result;
if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj,
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end))
return NULL;
if (PyTuple_Check(subobj)) {
Py_ssize_t i;
......@@ -7713,9 +7714,12 @@ unicode_endswith(PyUnicodeObject *self,
Py_RETURN_FALSE;
}
substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj);
if (substring == NULL)
if (substring == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_Format(PyExc_TypeError, "endswith first arg must be str, "
"unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name);
return NULL;
}
result = tailmatch(self, substring, start, end, +1);
Py_DECREF(substring);
return PyBool_FromLong(result);
......
......@@ -537,6 +537,23 @@ _PyGILState_Fini(void)
autoInterpreterState = NULL;
}
/* Reset the TLS key - called by PyOS_AfterFork.
* This should not be necessary, but some - buggy - pthread implementations
* don't flush TLS on fork, see issue #10517.
*/
void
_PyGILState_Reinit(void)
{
PyThreadState *tstate = PyGILState_GetThisThreadState();
PyThread_delete_key(autoTLSkey);
if ((autoTLSkey = PyThread_create_key()) == -1)
Py_FatalError("Could not allocate TLS entry");
/* re-associate the current thread state with the new key */
if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0)
Py_FatalError("Couldn't create autoTLSkey mapping");
}
/* When a thread state is created for a thread by some mechanism other than
PyGILState_Ensure, it's important that the GILState machinery knows about
it so it doesn't try to create another thread state for the thread (this is
......
......@@ -278,7 +278,7 @@ class Test:
for i in calibration_loops:
pass
t = timer() - t
prep_times.append(t)
prep_times.append(t / CALIBRATION_LOOPS)
min_prep_time = min(prep_times)
if _debug:
print
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment