diff options
-rw-r--r-- | Doc/library/argparse.rst | 405 | ||||
-rw-r--r-- | Doc/library/functools.rst | 10 | ||||
-rw-r--r-- | Lib/idlelib/EditorWindow.py | 4 | ||||
-rw-r--r-- | Lib/test/test_builtin.py | 34 | ||||
-rw-r--r-- | Lib/test/test_itertools.py | 117 | ||||
-rw-r--r-- | Lib/unittest/mock.py | 2 | ||||
-rw-r--r-- | Lib/unittest/test/testmock/testmock.py | 4 | ||||
-rw-r--r-- | Lib/urllib/parse.py | 9 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/NEWS | 5 | ||||
-rw-r--r-- | Modules/itertoolsmodule.c | 47 | ||||
-rw-r--r-- | Objects/abstract.c | 7 | ||||
-rw-r--r-- | Python/bltinmodule.c | 30 | ||||
-rw-r--r-- | Python/compile.c | 7 |
14 files changed, 239 insertions, 443 deletions
diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 71311412e3..f3eb9dd59e 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -137,40 +137,136 @@ ArgumentParser objects argument_default=None, conflict_handler='error', \ add_help=True) - Create a new :class:`ArgumentParser` object. Each parameter has its own more - detailed description below, but in short they are: + Create a new :class:`ArgumentParser` object. All parameters should be passed + as keyword arguments. Each parameter has its own more detailed description + below, but in short they are: - * description_ - Text to display before the argument help. + * prog_ - The name of the program (default: ``sys.argv[0]``) - * epilog_ - Text to display after the argument help. + * usage_ - The string describing the program usage (default: generated from + arguments added to parser) - * add_help_ - Add a -h/--help option to the parser. (default: ``True``) + * description_ - Text to display before the argument help (default: none) - * argument_default_ - Set the global default value for arguments. - (default: ``None``) + * epilog_ - Text to display after the argument help (default: none) * parents_ - A list of :class:`ArgumentParser` objects whose arguments should - also be included. + also be included + + * formatter_class_ - A class for customizing the help output - * prefix_chars_ - The set of characters that prefix optional arguments. + * prefix_chars_ - The set of characters that prefix optional arguments (default: '-') * fromfile_prefix_chars_ - The set of characters that prefix files from - which additional arguments should be read. (default: ``None``) - - * formatter_class_ - A class for customizing the help output. + which additional arguments should be read (default: ``None``) - * conflict_handler_ - Usually unnecessary, defines strategy for resolving - conflicting optionals. + * argument_default_ - The global default value for arguments + (default: ``None``) - * prog_ - The name of the program (default: - ``sys.argv[0]``) + * conflict_handler_ - The strategy for resolving conflicting optionals + (usually unnecessary) - * usage_ - The string describing the program usage (default: generated) + * add_help_ - Add a -h/--help option to the parser (default: ``True``) The following sections describe how each of these are used. +prog +^^^^ + +By default, :class:`ArgumentParser` objects uses ``sys.argv[0]`` to determine +how to display the name of the program in help messages. This default is almost +always desirable because it will make the help messages match how the program was +invoked on the command line. For example, consider a file named +``myprogram.py`` with the following code:: + + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('--foo', help='foo help') + args = parser.parse_args() + +The help for this program will display ``myprogram.py`` as the program name +(regardless of where the program was invoked from):: + + $ python myprogram.py --help + usage: myprogram.py [-h] [--foo FOO] + + optional arguments: + -h, --help show this help message and exit + --foo FOO foo help + $ cd .. + $ python subdir\myprogram.py --help + usage: myprogram.py [-h] [--foo FOO] + + optional arguments: + -h, --help show this help message and exit + --foo FOO foo help + +To change this default behavior, another value can be supplied using the +``prog=`` argument to :class:`ArgumentParser`:: + + >>> parser = argparse.ArgumentParser(prog='myprogram') + >>> parser.print_help() + usage: myprogram [-h] + + optional arguments: + -h, --help show this help message and exit + +Note that the program name, whether determined from ``sys.argv[0]`` or from the +``prog=`` argument, is available to help messages using the ``%(prog)s`` format +specifier. + +:: + + >>> parser = argparse.ArgumentParser(prog='myprogram') + >>> parser.add_argument('--foo', help='foo of the %(prog)s program') + >>> parser.print_help() + usage: myprogram [-h] [--foo FOO] + + optional arguments: + -h, --help show this help message and exit + --foo FOO foo of the myprogram program + + +usage +^^^^^ + +By default, :class:`ArgumentParser` calculates the usage message from the +arguments it contains:: + + >>> parser = argparse.ArgumentParser(prog='PROG') + >>> parser.add_argument('--foo', nargs='?', help='foo help') + >>> parser.add_argument('bar', nargs='+', help='bar help') + >>> parser.print_help() + usage: PROG [-h] [--foo [FOO]] bar [bar ...] + + positional arguments: + bar bar help + + optional arguments: + -h, --help show this help message and exit + --foo [FOO] foo help + +The default message can be overridden with the ``usage=`` keyword argument:: + + >>> parser = argparse.ArgumentParser(prog='PROG', usage='%(prog)s [options]') + >>> parser.add_argument('--foo', nargs='?', help='foo help') + >>> parser.add_argument('bar', nargs='+', help='bar help') + >>> parser.print_help() + usage: PROG [options] + + positional arguments: + bar bar help + + optional arguments: + -h, --help show this help message and exit + --foo [FOO] foo help + +The ``%(prog)s`` format specifier is available to fill in the program name in +your usage messages. + + description ^^^^^^^^^^^ @@ -218,122 +314,6 @@ line-wrapped, but this behavior can be adjusted with the formatter_class_ argument to :class:`ArgumentParser`. -add_help -^^^^^^^^ - -By default, ArgumentParser objects add an option which simply displays -the parser's help message. For example, consider a file named -``myprogram.py`` containing the following code:: - - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('--foo', help='foo help') - args = parser.parse_args() - -If ``-h`` or ``--help`` is supplied at the command line, the ArgumentParser -help will be printed:: - - $ python myprogram.py --help - usage: myprogram.py [-h] [--foo FOO] - - optional arguments: - -h, --help show this help message and exit - --foo FOO foo help - -Occasionally, it may be useful to disable the addition of this help option. -This can be achieved by passing ``False`` as the ``add_help=`` argument to -:class:`ArgumentParser`:: - - >>> parser = argparse.ArgumentParser(prog='PROG', add_help=False) - >>> parser.add_argument('--foo', help='foo help') - >>> parser.print_help() - usage: PROG [--foo FOO] - - optional arguments: - --foo FOO foo help - -The help option is typically ``-h/--help``. The exception to this is -if the ``prefix_chars=`` is specified and does not include ``-``, in -which case ``-h`` and ``--help`` are not valid options. In -this case, the first character in ``prefix_chars`` is used to prefix -the help options:: - - >>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='+/') - >>> parser.print_help() - usage: PROG [+h] - - optional arguments: - +h, ++help show this help message and exit - - -prefix_chars -^^^^^^^^^^^^ - -Most command-line options will use ``-`` as the prefix, e.g. ``-f/--foo``. -Parsers that need to support different or additional prefix -characters, e.g. for options -like ``+f`` or ``/foo``, may specify them using the ``prefix_chars=`` argument -to the ArgumentParser constructor:: - - >>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='-+') - >>> parser.add_argument('+f') - >>> parser.add_argument('++bar') - >>> parser.parse_args('+f X ++bar Y'.split()) - Namespace(bar='Y', f='X') - -The ``prefix_chars=`` argument defaults to ``'-'``. Supplying a set of -characters that does not include ``-`` will cause ``-f/--foo`` options to be -disallowed. - - -fromfile_prefix_chars -^^^^^^^^^^^^^^^^^^^^^ - -Sometimes, for example when dealing with a particularly long argument lists, it -may make sense to keep the list of arguments in a file rather than typing it out -at the command line. If the ``fromfile_prefix_chars=`` argument is given to the -:class:`ArgumentParser` constructor, then arguments that start with any of the -specified characters will be treated as files, and will be replaced by the -arguments they contain. For example:: - - >>> with open('args.txt', 'w') as fp: - ... fp.write('-f\nbar') - >>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@') - >>> parser.add_argument('-f') - >>> parser.parse_args(['-f', 'foo', '@args.txt']) - Namespace(f='bar') - -Arguments read from a file must by default be one per line (but see also -: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. - - -argument_default -^^^^^^^^^^^^^^^^ - -Generally, argument defaults are specified either by passing a default to -: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) - >>> parser.add_argument('--foo') - >>> parser.add_argument('bar', nargs='?') - >>> parser.parse_args(['--foo', '1', 'BAR']) - Namespace(bar='BAR', foo='1') - >>> parser.parse_args([]) - Namespace() - - parents ^^^^^^^ @@ -471,6 +451,74 @@ as the regular formatter does):: --foo int +prefix_chars +^^^^^^^^^^^^ + +Most command-line options will use ``-`` as the prefix, e.g. ``-f/--foo``. +Parsers that need to support different or additional prefix +characters, e.g. for options +like ``+f`` or ``/foo``, may specify them using the ``prefix_chars=`` argument +to the ArgumentParser constructor:: + + >>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='-+') + >>> parser.add_argument('+f') + >>> parser.add_argument('++bar') + >>> parser.parse_args('+f X ++bar Y'.split()) + Namespace(bar='Y', f='X') + +The ``prefix_chars=`` argument defaults to ``'-'``. Supplying a set of +characters that does not include ``-`` will cause ``-f/--foo`` options to be +disallowed. + + +fromfile_prefix_chars +^^^^^^^^^^^^^^^^^^^^^ + +Sometimes, for example when dealing with a particularly long argument lists, it +may make sense to keep the list of arguments in a file rather than typing it out +at the command line. If the ``fromfile_prefix_chars=`` argument is given to the +:class:`ArgumentParser` constructor, then arguments that start with any of the +specified characters will be treated as files, and will be replaced by the +arguments they contain. For example:: + + >>> with open('args.txt', 'w') as fp: + ... fp.write('-f\nbar') + >>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@') + >>> parser.add_argument('-f') + >>> parser.parse_args(['-f', 'foo', '@args.txt']) + Namespace(f='bar') + +Arguments read from a file must by default be one per line (but see also +: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. + + +argument_default +^^^^^^^^^^^^^^^^ + +Generally, argument defaults are specified either by passing a default to +: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) + >>> parser.add_argument('--foo') + >>> parser.add_argument('bar', nargs='?') + >>> parser.parse_args(['--foo', '1', 'BAR']) + Namespace(bar='BAR', foo='1') + >>> parser.parse_args([]) + Namespace() + + conflict_handler ^^^^^^^^^^^^^^^^ @@ -508,22 +556,20 @@ action is retained as the ``-f`` action, because only the ``--foo`` option string was overridden. -prog -^^^^ +add_help +^^^^^^^^ -By default, :class:`ArgumentParser` objects uses ``sys.argv[0]`` to determine -how to display the name of the program in help messages. This default is almost -always desirable because it will make the help messages match how the program was -invoked on the command line. For example, consider a file named -``myprogram.py`` with the following code:: +By default, ArgumentParser objects add an option which simply displays +the parser's help message. For example, consider a file named +``myprogram.py`` containing the following code:: import argparse parser = argparse.ArgumentParser() parser.add_argument('--foo', help='foo help') args = parser.parse_args() -The help for this program will display ``myprogram.py`` as the program name -(regardless of where the program was invoked from):: +If ``-h`` or ``--help`` is supplied at the command line, the ArgumentParser +help will be printed:: $ python myprogram.py --help usage: myprogram.py [-h] [--foo FOO] @@ -531,76 +577,31 @@ The help for this program will display ``myprogram.py`` as the program name optional arguments: -h, --help show this help message and exit --foo FOO foo help - $ cd .. - $ python subdir\myprogram.py --help - usage: myprogram.py [-h] [--foo FOO] - optional arguments: - -h, --help show this help message and exit - --foo FOO foo help - -To change this default behavior, another value can be supplied using the -``prog=`` argument to :class:`ArgumentParser`:: - - >>> parser = argparse.ArgumentParser(prog='myprogram') - >>> parser.print_help() - usage: myprogram [-h] - - optional arguments: - -h, --help show this help message and exit - -Note that the program name, whether determined from ``sys.argv[0]`` or from the -``prog=`` argument, is available to help messages using the ``%(prog)s`` format -specifier. - -:: - - >>> parser = argparse.ArgumentParser(prog='myprogram') - >>> parser.add_argument('--foo', help='foo of the %(prog)s program') - >>> parser.print_help() - usage: myprogram [-h] [--foo FOO] - - optional arguments: - -h, --help show this help message and exit - --foo FOO foo of the myprogram program - - -usage -^^^^^ - -By default, :class:`ArgumentParser` calculates the usage message from the -arguments it contains:: +Occasionally, it may be useful to disable the addition of this help option. +This can be achieved by passing ``False`` as the ``add_help=`` argument to +:class:`ArgumentParser`:: - >>> parser = argparse.ArgumentParser(prog='PROG') - >>> parser.add_argument('--foo', nargs='?', help='foo help') - >>> parser.add_argument('bar', nargs='+', help='bar help') + >>> parser = argparse.ArgumentParser(prog='PROG', add_help=False) + >>> parser.add_argument('--foo', help='foo help') >>> parser.print_help() - usage: PROG [-h] [--foo [FOO]] bar [bar ...] - - positional arguments: - bar bar help + usage: PROG [--foo FOO] optional arguments: - -h, --help show this help message and exit - --foo [FOO] foo help + --foo FOO foo help -The default message can be overridden with the ``usage=`` keyword argument:: +The help option is typically ``-h/--help``. The exception to this is +if the ``prefix_chars=`` is specified and does not include ``-``, in +which case ``-h`` and ``--help`` are not valid options. In +this case, the first character in ``prefix_chars`` is used to prefix +the help options:: - >>> parser = argparse.ArgumentParser(prog='PROG', usage='%(prog)s [options]') - >>> parser.add_argument('--foo', nargs='?', help='foo help') - >>> parser.add_argument('bar', nargs='+', help='bar help') + >>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='+/') >>> parser.print_help() - usage: PROG [options] - - positional arguments: - bar bar help + usage: PROG [-h] optional arguments: - -h, --help show this help message and exit - --foo [FOO] foo help - -The ``%(prog)s`` format specifier is available to fill in the program name in -your usage messages. + -h, --help show this help message and exit The add_argument() method diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index f5c6608e1d..d8fcf0f6cb 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -79,7 +79,7 @@ The :mod:`functools` module defines the following functions: Example of an LRU cache for static web content:: - @lru_cache(maxsize=20) + @lru_cache(maxsize=32) def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' resource = 'http://www.python.org/dev/peps/pep-%04d/' % num @@ -93,8 +93,8 @@ The :mod:`functools` module defines the following functions: ... pep = get_pep(n) ... print(n, len(pep)) - >>> print(get_pep.cache_info()) - CacheInfo(hits=3, misses=8, maxsize=20, currsize=8) + >>> get_pep.cache_info() + CacheInfo(hits=3, misses=8, maxsize=32, currsize=8) Example of efficiently computing `Fibonacci numbers <http://en.wikipedia.org/wiki/Fibonacci_number>`_ @@ -108,10 +108,10 @@ The :mod:`functools` module defines the following functions: return n return fib(n-1) + fib(n-2) - >>> print([fib(n) for n in range(16)]) + >>> [fib(n) for n in range(16)] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] - >>> print(fib.cache_info()) + >>> fib.cache_info() CacheInfo(hits=28, misses=16, maxsize=None, currsize=16) .. versionadded:: 3.2 diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py index 565cf367e2..148a1daaa0 100644 --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -1433,6 +1433,7 @@ class EditorWindow(object): def tabify_region_event(self, event): head, tail, chars, lines = self.get_region() tabwidth = self._asktabwidth() + if tabwidth is None: return for pos in range(len(lines)): line = lines[pos] if line: @@ -1444,6 +1445,7 @@ class EditorWindow(object): def untabify_region_event(self, event): head, tail, chars, lines = self.get_region() tabwidth = self._asktabwidth() + if tabwidth is None: return for pos in range(len(lines)): lines[pos] = lines[pos].expandtabs(tabwidth) self.set_region(head, tail, chars, lines) @@ -1537,7 +1539,7 @@ class EditorWindow(object): parent=self.text, initialvalue=self.indentwidth, minvalue=2, - maxvalue=16) or self.tabwidth + maxvalue=16) # Guess indentwidth from text content. # Return guessed indentwidth. This should not be believed unless diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index b601ea4a03..f46f8d561c 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1564,40 +1564,8 @@ class TestSorted(unittest.TestCase): data = 'The quick Brown fox Jumped over The lazy Dog'.split() self.assertRaises(TypeError, sorted, data, None, lambda x,y: 0) -class TestRecursionLimit(unittest.TestCase): - # Issue #14010 - recursionlimit = sys.getrecursionlimit() - - def test_filter(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = filter(bool, it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_map(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = map(int, it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_zip(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = zip(it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_main(verbose=None): - test_classes = (BuiltinTest, TestSorted, TestRecursionLimit) + test_classes = (BuiltinTest, TestSorted) run_unittest(*test_classes) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 2a395b507c..fdf798497e 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -1808,121 +1808,6 @@ class SubclassWithKwargsTest(unittest.TestCase): self.assertNotIn("does not take keyword arguments", err.args[0]) -class TestRecursionLimit(unittest.TestCase): - # Issue #14010 - recursionlimit = sys.getrecursionlimit() - - def test_accumulate(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = accumulate(it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_chain(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = chain(it, ()) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_compress(self): - data = (0, 1) - selectors = (True, True) - it = data - for _ in range(self.recursionlimit): - it = compress(it, selectors) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - it = selectors - for _ in range(self.recursionlimit): - it = compress(data, it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_cycle(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = cycle(it) - with self.assertRaises(RuntimeError): - for _ in range(3): - next(it) - del it - - def test_dropwhile(self): - it = (0, 1, 0) - for _ in range(self.recursionlimit): - it = dropwhile(bool, it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_filterfalse(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = filterfalse(bool, it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_groupby(self): - key = operator.itemgetter(0) - it = ((0, []), (1, [])) - for _ in range(self.recursionlimit): - it = groupby(it, key) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_islice(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = islice(it, 2) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_starmap(self): - it = 'ab' - for _ in range(self.recursionlimit): - it = starmap(tuple, it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_takewhile(self): - it = (1, 0) - for _ in range(self.recursionlimit): - it = takewhile(bool, it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - def test_zip_longest(self): - it = (0, 1) - for _ in range(self.recursionlimit): - it = zip_longest(it) - with self.assertRaises(RuntimeError): - for _ in it: - pass - del it - - libreftest = """ Doctest for examples in the library reference: libitertools.tex @@ -2157,7 +2042,7 @@ __test__ = {'libreftest' : libreftest} def test_main(verbose=None): test_classes = (TestBasicOps, TestVariousIteratorArgs, TestGC, RegressionTests, LengthTransparency, - SubclassWithKwargsTest, TestExamples, TestRecursionLimit) + SubclassWithKwargsTest, TestExamples) support.run_unittest(*test_classes) # verify reference counting diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 5a1db8af06..dc5c033739 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -931,6 +931,8 @@ class CallableMixin(Base): result = next(effect) if _is_exception(result): raise result + if result is DEFAULT: + result = self.return_value return result ret_val = effect(*args, **kwargs) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index 475a826b50..127786c587 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -978,6 +978,10 @@ class MockTest(unittest.TestCase): self.assertRaises(StopIteration, mock) self.assertIs(mock.side_effect, this_iter) + def test_side_effect_iterator_default(self): + mock = Mock(return_value=2) + mock.side_effect = iter([1, DEFAULT]) + self.assertEqual([mock(), mock()], [1, 2]) def test_assert_has_calls_any_order(self): mock = Mock() diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index abe5d0d868..b49b7a1f26 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -846,7 +846,6 @@ def splittype(url): """splittype('type:opaquestring') --> 'type', 'opaquestring'.""" global _typeprog if _typeprog is None: - import re _typeprog = re.compile('^([^/:]+):') match = _typeprog.match(url) @@ -860,7 +859,6 @@ def splithost(url): """splithost('//host[:port]/path') --> 'host[:port]', '/path'.""" global _hostprog if _hostprog is None: - import re _hostprog = re.compile('^//([^/?]*)(.*)$') match = _hostprog.match(url) @@ -877,7 +875,6 @@ def splituser(host): """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" global _userprog if _userprog is None: - import re _userprog = re.compile('^(.*)@(.*)$') match = _userprog.match(host) @@ -889,7 +886,6 @@ def splitpasswd(user): """splitpasswd('user:passwd') -> 'user', 'passwd'.""" global _passwdprog if _passwdprog is None: - import re _passwdprog = re.compile('^([^:]*):(.*)$',re.S) match = _passwdprog.match(user) @@ -902,7 +898,6 @@ def splitport(host): """splitport('host:port') --> 'host', 'port'.""" global _portprog if _portprog is None: - import re _portprog = re.compile('^(.*):([0-9]+)$') match = _portprog.match(host) @@ -917,7 +912,6 @@ def splitnport(host, defport=-1): Return None if ':' but not a valid number.""" global _nportprog if _nportprog is None: - import re _nportprog = re.compile('^(.*):(.*)$') match = _nportprog.match(host) @@ -936,7 +930,6 @@ def splitquery(url): """splitquery('/path?query') --> '/path', 'query'.""" global _queryprog if _queryprog is None: - import re _queryprog = re.compile('^(.*)\?([^?]*)$') match = _queryprog.match(url) @@ -948,7 +941,6 @@ def splittag(url): """splittag('/path#tag') --> '/path', 'tag'.""" global _tagprog if _tagprog is None: - import re _tagprog = re.compile('^(.*)#([^#]*)$') match = _tagprog.match(url) @@ -966,7 +958,6 @@ def splitvalue(attr): """splitvalue('attr=value') --> 'attr', 'value'.""" global _valueprog if _valueprog is None: - import re _valueprog = re.compile('^([^=]*)=(.*)$') match = _valueprog.match(attr) @@ -722,6 +722,7 @@ Luke Kenneth Casson Leighton Tshepang Lekhonkhobe Marc-André Lemburg John Lenton +Kostyantyn Leschenko Benno Leslie Christopher Tur Lesniewski-Laas Alain Leufroy @@ -10,9 +10,6 @@ What's New in Python 3.4.0 Alpha 1? Core and Builtins ----------------- -- Issue #14010: Fix a crash when iterating or deleting deeply nested filters - (builting and in itertools module, i.e. map(), itertools.chain(), etc). - - Issue #17469: Fix _Py_GetAllocatedBlocks() and sys.getallocatedblocks() when running on valgrind. @@ -1016,6 +1013,8 @@ _ Issue #17385: Fix quadratic behavior in threading.Condition. The FIFO IDLE ---- +- Issue #16887: IDLE now accepts Cancel in tabify/untabify dialog box. + - Issue #14254: IDLE now handles readline correctly across shell restarts. - Issue #17614: IDLE no longer raises exception when quickly closing a file. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 74c5d98a13..644104e85b 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -54,14 +54,12 @@ static void groupby_dealloc(groupbyobject *gbo) { PyObject_GC_UnTrack(gbo); - Py_TRASHCAN_SAFE_BEGIN(gbo) Py_XDECREF(gbo->it); Py_XDECREF(gbo->keyfunc); Py_XDECREF(gbo->tgtkey); Py_XDECREF(gbo->currkey); Py_XDECREF(gbo->currvalue); Py_TYPE(gbo)->tp_free(gbo); - Py_TRASHCAN_SAFE_END(gbo) } static int @@ -913,11 +911,9 @@ static void cycle_dealloc(cycleobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->saved); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -1092,11 +1088,9 @@ static void dropwhile_dealloc(dropwhileobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -1117,10 +1111,7 @@ dropwhile_next(dropwhileobject *lz) iternext = *Py_TYPE(it)->tp_iternext; for (;;) { - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; item = iternext(it); - Py_LeaveRecursiveCall(); if (item == NULL) return NULL; if (lz->start == 1) @@ -1266,11 +1257,9 @@ static void takewhile_dealloc(takewhileobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -1291,10 +1280,7 @@ takewhile_next(takewhileobject *lz) if (lz->stop == 1) return NULL; - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; item = (*Py_TYPE(it)->tp_iternext)(it); - Py_LeaveRecursiveCall(); if (item == NULL) return NULL; @@ -1486,10 +1472,8 @@ static void islice_dealloc(isliceobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -1510,10 +1494,7 @@ islice_next(isliceobject *lz) iternext = *Py_TYPE(it)->tp_iternext; while (lz->cnt < lz->next) { - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; item = iternext(it); - Py_LeaveRecursiveCall(); if (item == NULL) return NULL; Py_DECREF(item); @@ -1521,10 +1502,7 @@ islice_next(isliceobject *lz) } if (stop != -1 && lz->cnt >= stop) return NULL; - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; item = iternext(it); - Py_LeaveRecursiveCall(); if (item == NULL) return NULL; lz->cnt++; @@ -1675,11 +1653,9 @@ static void starmap_dealloc(starmapobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -1697,10 +1673,7 @@ starmap_next(starmapobject *lz) PyObject *result; PyObject *it = lz->it; - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; args = (*Py_TYPE(it)->tp_iternext)(it); - Py_LeaveRecursiveCall(); if (args == NULL) return NULL; if (!PyTuple_CheckExact(args)) { @@ -1836,11 +1809,9 @@ static void chain_dealloc(chainobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->active); Py_XDECREF(lz->source); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -3369,12 +3340,10 @@ static void accumulate_dealloc(accumulateobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->binop); Py_XDECREF(lz->total); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -3545,11 +3514,9 @@ static void compress_dealloc(compressobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->data); Py_XDECREF(lz->selectors); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -3576,16 +3543,11 @@ compress_next(compressobject *lz) exception first). */ - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; datum = datanext(data); - if (datum == NULL) { - Py_LeaveRecursiveCall(); + if (datum == NULL) return NULL; - } selector = selectornext(selectors); - Py_LeaveRecursiveCall(); if (selector == NULL) { Py_DECREF(datum); return NULL; @@ -3712,11 +3674,9 @@ static void filterfalse_dealloc(filterfalseobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -3737,10 +3697,7 @@ filterfalse_next(filterfalseobject *lz) iternext = *Py_TYPE(it)->tp_iternext; for (;;) { - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; item = iternext(it); - Py_LeaveRecursiveCall(); if (item == NULL) return NULL; @@ -4304,12 +4261,10 @@ static void zip_longest_dealloc(ziplongestobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->ittuple); Py_XDECREF(lz->result); Py_XDECREF(lz->fillvalue); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int diff --git a/Objects/abstract.c b/Objects/abstract.c index 9b31d7a793..4326cfabd7 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1238,7 +1238,7 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) to be an int or have an __int__ method. Steals integral's reference. error_format will be used to create the TypeError if integral isn't actually an Integral instance. error_format should be a format string - that can accept a char* naming integral's type. + that can accept a char* naming integral's type. */ static PyObject * convert_integral_to_int(PyObject *integral, const char *error_format) @@ -1257,7 +1257,7 @@ convert_integral_to_int(PyObject *integral, const char *error_format) } PyErr_Format(PyExc_TypeError, error_format, Py_TYPE(integral)->tp_name); Py_DECREF(integral); - return NULL; + return NULL; } @@ -2702,10 +2702,7 @@ PyObject * PyIter_Next(PyObject *iter) { PyObject *result; - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; result = (*iter->ob_type->tp_iternext)(iter); - Py_LeaveRecursiveCall(); if (result == NULL && PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 6344c686cc..a486b4978c 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -391,11 +391,9 @@ static void filter_dealloc(filterobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -416,10 +414,7 @@ filter_next(filterobject *lz) iternext = *Py_TYPE(it)->tp_iternext; for (;;) { - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; item = iternext(it); - Py_LeaveRecursiveCall(); if (item == NULL) return NULL; @@ -1036,11 +1031,9 @@ static void map_dealloc(mapobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->iters); Py_XDECREF(lz->func); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -2227,11 +2220,9 @@ static void zip_dealloc(zipobject *lz) { PyObject_GC_UnTrack(lz); - Py_TRASHCAN_SAFE_BEGIN(lz) Py_XDECREF(lz->ittuple); Py_XDECREF(lz->result); Py_TYPE(lz)->tp_free(lz); - Py_TRASHCAN_SAFE_END(lz) } static int @@ -2254,15 +2245,15 @@ zip_next(zipobject *lz) if (tuplesize == 0) return NULL; - if (Py_EnterRecursiveCall(" while iterating")) - return NULL; if (Py_REFCNT(result) == 1) { Py_INCREF(result); for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); item = (*Py_TYPE(it)->tp_iternext)(it); - if (item == NULL) - goto error; + if (item == NULL) { + Py_DECREF(result); + return NULL; + } olditem = PyTuple_GET_ITEM(result, i); PyTuple_SET_ITEM(result, i, item); Py_DECREF(olditem); @@ -2270,21 +2261,18 @@ zip_next(zipobject *lz) } else { result = PyTuple_New(tuplesize); if (result == NULL) - goto error; + return NULL; for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); item = (*Py_TYPE(it)->tp_iternext)(it); - if (item == NULL) - goto error; + if (item == NULL) { + Py_DECREF(result); + return NULL; + } PyTuple_SET_ITEM(result, i, item); } } - Py_LeaveRecursiveCall(); return result; -error: - Py_XDECREF(result); - Py_LeaveRecursiveCall(); - return NULL; } static PyObject * diff --git a/Python/compile.c b/Python/compile.c index 0aca8bd2e9..842ed50bec 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -248,8 +248,11 @@ _Py_Mangle(PyObject *privateobj, PyObject *ident) } plen -= ipriv; - assert(1 <= PY_SSIZE_T_MAX - nlen); - assert(1 + nlen <= PY_SSIZE_T_MAX - plen); + if (plen + nlen >= PY_SSIZE_T_MAX - 1) { + PyErr_SetString(PyExc_OverflowError, + "private identifier too large to be mangled"); + return NULL; + } maxchar = PyUnicode_MAX_CHAR_VALUE(ident); if (PyUnicode_MAX_CHAR_VALUE(privateobj) > maxchar) |