Python-checkins
Threads by month
- ----- 2024 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
June 2019
- 2 participants
- 665 discussions
Doc: Correct the creation year and the credits of the Logo Programming language (GH-13520)
by Cheryl Sabella 01 Jun '19
by Cheryl Sabella 01 Jun '19
01 Jun '19
https://github.com/python/cpython/commit/66501058fef76a5d77e6879f6da3282f0a…
commit: 66501058fef76a5d77e6879f6da3282f0a9eef1b
branch: master
author: Stéphane Wirtel <stephane(a)wirtel.be>
committer: Cheryl Sabella <cheryl.sabella(a)gmail.com>
date: 2019-06-01T07:41:33-04:00
summary:
Doc: Correct the creation year and the credits of the Logo Programming language (GH-13520)
files:
M Doc/library/turtle.rst
diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst
index 3d90d3cbd974..7f9f0c343867 100644
--- a/Doc/library/turtle.rst
+++ b/Doc/library/turtle.rst
@@ -20,8 +20,8 @@ Introduction
============
Turtle graphics is a popular way for introducing programming to kids. It was
-part of the original Logo programming language developed by Wally Feurzig and
-Seymour Papert in 1966.
+part of the original Logo programming language developed by Wally Feurzeig,
+Seymour Papert and Cynthia Solomon in 1967.
Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it the
command ``turtle.forward(15)``, and it moves (on-screen!) 15 pixels in the
1
0
Move whats-new entry for math.factorial to the math module section. (GH-13723)
by Mark Dickinson 01 Jun '19
by Mark Dickinson 01 Jun '19
01 Jun '19
https://github.com/python/cpython/commit/a0adffb90287900a9e2c809ce2c1bbe481…
commit: a0adffb90287900a9e2c809ce2c1bbe481ac7dd0
branch: master
author: Mark Dickinson <mdickinson(a)enthought.com>
committer: GitHub <noreply(a)github.com>
date: 2019-06-01T12:21:53+01:00
summary:
Move whats-new entry for math.factorial to the math module section. (GH-13723)
files:
M Doc/whatsnew/3.8.rst
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index bc7c9ef37442..2d5291102d2a 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -460,6 +460,9 @@ numbers. (Contributed by Pablo Galindo in :issue:`35606`)
Added new function :func:`math.isqrt` for computing integer square roots.
(Contributed by Mark Dickinson in :issue:`36887`.)
+The function :func:`math.factorial` no longer accepts arguments that are not
+int-like. (Contributed by Pablo Galindo in :issue:`33083`.)
+
mmap
----
@@ -1140,9 +1143,6 @@ Changes in the Python API
success; an exception was raised on error under Unix.
(Contributed by Berker Peksag in :issue:`2122`.)
-* The function :func:`math.factorial` no longer accepts arguments that are not
- int-like. (Contributed by Pablo Galindo in :issue:`33083`.)
-
* :mod:`xml.dom.minidom` and :mod:`xml.sax` modules no longer process
external entities by default.
(Contributed by Christian Heimes in :issue:`17239`.)
1
0
bpo-36813: Fix QueueListener to call task_done() upon termination. (GH-13113)
by Miss Islington (bot) 01 Jun '19
by Miss Islington (bot) 01 Jun '19
01 Jun '19
https://github.com/python/cpython/commit/f286e0373feda0955c910a9fe4ef99cd2c…
commit: f286e0373feda0955c910a9fe4ef99cd2c40969e
branch: 3.7
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: GitHub <noreply(a)github.com>
date: 2019-06-01T02:36:29-07:00
summary:
bpo-36813: Fix QueueListener to call task_done() upon termination. (GH-13113)
Fixed QueueListener in order to avoid random deadlocks.
Unable to add regression tests atm due to time constraints, will add it in a bit.
Regarding implementation, although it's nested, it does not cause performance issues whatsoever, and does not call task_done() in case of an exception (which is the right thing to do IMHO).
https://bugs.python.org/issue36813
(cherry picked from commit 6b282e18877ec84e927b381b4ce187eaf4ba3dd7)
Co-authored-by: Bar Harel <bzvi7919(a)gmail.com>
files:
A Misc/NEWS.d/next/Library/2019-05-06-18-28-38.bpo-36813.NXD0KZ.rst
M Lib/logging/handlers.py
M Lib/test/test_logging.py
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 3727bf0677cd..a913d27389ab 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -1477,6 +1477,8 @@ def _monitor(self):
try:
record = self.dequeue(True)
if record is self._sentinel:
+ if has_task_done:
+ q.task_done()
break
self.handle(record)
if has_task_done:
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index d12e1e57455d..97c13a4c5214 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -3495,6 +3495,16 @@ def test_no_messages_in_queue_after_stop(self):
[m.msg if isinstance(m, logging.LogRecord)
else m for m in items]))
+ def test_calls_task_done_after_stop(self):
+ # Issue 36813: Make sure queue.join does not deadlock.
+ log_queue = queue.Queue()
+ listener = logging.handlers.QueueListener(log_queue)
+ listener.start()
+ listener.stop()
+ with self.assertRaises(ValueError):
+ # Make sure all tasks are done and .join won't block.
+ log_queue.task_done()
+
ZERO = datetime.timedelta(0)
diff --git a/Misc/NEWS.d/next/Library/2019-05-06-18-28-38.bpo-36813.NXD0KZ.rst b/Misc/NEWS.d/next/Library/2019-05-06-18-28-38.bpo-36813.NXD0KZ.rst
new file mode 100644
index 000000000000..e89358aa4051
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-06-18-28-38.bpo-36813.NXD0KZ.rst
@@ -0,0 +1,2 @@
+Fix :class:`~logging.handlers.QueueListener` to call ``queue.task_done()``
+upon stopping. Patch by Bar Harel.
1
0
bpo-36813: Fix QueueListener to call task_done() upon termination. (GH-13113)
by Miss Islington (bot) 01 Jun '19
by Miss Islington (bot) 01 Jun '19
01 Jun '19
https://github.com/python/cpython/commit/6b282e18877ec84e927b381b4ce187eaf4…
commit: 6b282e18877ec84e927b381b4ce187eaf4ba3dd7
branch: master
author: Bar Harel <bzvi7919(a)gmail.com>
committer: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
date: 2019-06-01T02:19:09-07:00
summary:
bpo-36813: Fix QueueListener to call task_done() upon termination. (GH-13113)
Fixed QueueListener in order to avoid random deadlocks.
Unable to add regression tests atm due to time constraints, will add it in a bit.
Regarding implementation, although it's nested, it does not cause performance issues whatsoever, and does not call task_done() in case of an exception (which is the right thing to do IMHO).
https://bugs.python.org/issue36813
files:
A Misc/NEWS.d/next/Library/2019-05-06-18-28-38.bpo-36813.NXD0KZ.rst
M Lib/logging/handlers.py
M Lib/test/test_logging.py
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 3727bf0677cd..a913d27389ab 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -1477,6 +1477,8 @@ def _monitor(self):
try:
record = self.dequeue(True)
if record is self._sentinel:
+ if has_task_done:
+ q.task_done()
break
self.handle(record)
if has_task_done:
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index b884753ad397..50148dc2f252 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -3633,6 +3633,16 @@ def test_no_messages_in_queue_after_stop(self):
[m.msg if isinstance(m, logging.LogRecord)
else m for m in items]))
+ def test_calls_task_done_after_stop(self):
+ # Issue 36813: Make sure queue.join does not deadlock.
+ log_queue = queue.Queue()
+ listener = logging.handlers.QueueListener(log_queue)
+ listener.start()
+ listener.stop()
+ with self.assertRaises(ValueError):
+ # Make sure all tasks are done and .join won't block.
+ log_queue.task_done()
+
ZERO = datetime.timedelta(0)
diff --git a/Misc/NEWS.d/next/Library/2019-05-06-18-28-38.bpo-36813.NXD0KZ.rst b/Misc/NEWS.d/next/Library/2019-05-06-18-28-38.bpo-36813.NXD0KZ.rst
new file mode 100644
index 000000000000..e89358aa4051
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-06-18-28-38.bpo-36813.NXD0KZ.rst
@@ -0,0 +1,2 @@
+Fix :class:`~logging.handlers.QueueListener` to call ``queue.task_done()``
+upon stopping. Patch by Bar Harel.
1
0
https://github.com/python/cpython/commit/70c5f2ae6e6a07d44a8d3f3202ea01bf69…
commit: 70c5f2ae6e6a07d44a8d3f3202ea01bf697e05db
branch: master
author: Serhiy Storchaka <storchaka(a)gmail.com>
committer: GitHub <noreply(a)github.com>
date: 2019-06-01T11:38:24+03:00
summary:
Use more PEP 570 syntax in the documentation. (GH-13720)
files:
M Doc/faq/programming.rst
M Doc/howto/logging-cookbook.rst
M Doc/library/functools.rst
M Doc/reference/datamodel.rst
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
index 9660a701427f..a00c6a053ef1 100644
--- a/Doc/faq/programming.rst
+++ b/Doc/faq/programming.rst
@@ -554,8 +554,8 @@ desired effect in a number of ways.
5) Or bundle up values in a class instance::
class callByRef:
- def __init__(self, **args):
- for (key, value) in args.items():
+ def __init__(self, /, **args):
+ for key, value in args.items():
setattr(self, key, value)
def func4(args):
diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst
index 4956aa0dd957..71f9fc920fdf 100644
--- a/Doc/howto/logging-cookbook.rst
+++ b/Doc/howto/logging-cookbook.rst
@@ -579,7 +579,7 @@ information. When you call one of the logging methods on an instance of
information in the delegated call. Here's a snippet from the code of
:class:`LoggerAdapter`::
- def debug(self, msg, *args, **kwargs):
+ def debug(self, msg, /, *args, **kwargs):
"""
Delegate a debug call to the underlying logger, after adding
contextual information from this adapter instance.
@@ -1079,7 +1079,7 @@ call ``str()`` on that object to get the actual format string. Consider the
following two classes::
class BraceMessage:
- def __init__(self, fmt, *args, **kwargs):
+ def __init__(self, fmt, /, *args, **kwargs):
self.fmt = fmt
self.args = args
self.kwargs = kwargs
@@ -1088,7 +1088,7 @@ following two classes::
return self.fmt.format(*self.args, **self.kwargs)
class DollarMessage:
- def __init__(self, fmt, **kwargs):
+ def __init__(self, fmt, /, **kwargs):
self.fmt = fmt
self.kwargs = kwargs
@@ -1143,7 +1143,7 @@ to the above, as in the following example::
import logging
- class Message(object):
+ class Message:
def __init__(self, fmt, args):
self.fmt = fmt
self.args = args
@@ -1155,7 +1155,7 @@ to the above, as in the following example::
def __init__(self, logger, extra=None):
super(StyleAdapter, self).__init__(logger, extra or {})
- def log(self, level, msg, *args, **kwargs):
+ def log(self, level, msg, /, *args, **kwargs):
if self.isEnabledFor(level):
msg, kwargs = self.process(msg, kwargs)
self.logger._log(level, Message(msg, args), (), **kwargs)
@@ -1301,7 +1301,7 @@ You can also subclass :class:`QueueListener` to get messages from other kinds
of queues, for example a ZeroMQ 'subscribe' socket. Here's an example::
class ZeroMQSocketListener(QueueListener):
- def __init__(self, uri, *handlers, **kwargs):
+ def __init__(self, uri, /, *handlers, **kwargs):
self.ctx = kwargs.get('ctx') or zmq.Context()
socket = zmq.Socket(self.ctx, zmq.SUB)
socket.setsockopt_string(zmq.SUBSCRIBE, '') # subscribe to everything
@@ -1706,8 +1706,8 @@ which uses JSON to serialise the event in a machine-parseable manner::
import json
import logging
- class StructuredMessage(object):
- def __init__(self, message, **kwargs):
+ class StructuredMessage:
+ def __init__(self, message, /, **kwargs):
self.message = message
self.kwargs = kwargs
@@ -1750,8 +1750,8 @@ as in the following complete example::
return o.encode('unicode_escape').decode('ascii')
return super(Encoder, self).default(o)
- class StructuredMessage(object):
- def __init__(self, message, **kwargs):
+ class StructuredMessage:
+ def __init__(self, message, /, **kwargs):
self.message = message
self.kwargs = kwargs
@@ -1982,8 +1982,8 @@ object as a message format string, and that the logging package will call
:func:`str` on that object to get the actual format string. Consider the
following two classes::
- class BraceMessage(object):
- def __init__(self, fmt, *args, **kwargs):
+ class BraceMessage:
+ def __init__(self, fmt, /, *args, **kwargs):
self.fmt = fmt
self.args = args
self.kwargs = kwargs
@@ -1991,8 +1991,8 @@ following two classes::
def __str__(self):
return self.fmt.format(*self.args, **self.kwargs)
- class DollarMessage(object):
- def __init__(self, fmt, **kwargs):
+ class DollarMessage:
+ def __init__(self, fmt, /, **kwargs):
self.fmt = fmt
self.kwargs = kwargs
@@ -2457,7 +2457,7 @@ scope of the context manager::
import logging
import sys
- class LoggingContext(object):
+ class LoggingContext:
def __init__(self, logger, level=None, handler=None, close=True):
self.logger = logger
self.level = level
diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst
index 654a3efa214b..3a0b554e923c 100644
--- a/Doc/library/functools.rst
+++ b/Doc/library/functools.rst
@@ -252,7 +252,7 @@ The :mod:`functools` module defines the following functions:
18
-.. class:: partialmethod(func, *args, **keywords)
+.. class:: partialmethod(func, /, *args, **keywords)
Return a new :class:`partialmethod` descriptor which behaves
like :class:`partial` except that it is designed to be used as a method
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index 8b4d889535fb..c566dfdf856d 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1809,7 +1809,7 @@ class defining the method.
class, as in::
class Philosopher:
- def __init_subclass__(cls, default_name, **kwargs):
+ def __init_subclass__(cls, /, default_name, **kwargs):
super().__init_subclass__(**kwargs)
cls.default_name = default_name
1
0
bpo-37116: Use PEP 570 syntax for positional-only parameters. (GH-13700)
by Serhiy Storchaka 01 Jun '19
by Serhiy Storchaka 01 Jun '19
01 Jun '19
https://github.com/python/cpython/commit/2085bd0877e17ad4d98a4586d5eabb6fae…
commit: 2085bd0877e17ad4d98a4586d5eabb6faecbb190
branch: master
author: Serhiy Storchaka <storchaka(a)gmail.com>
committer: GitHub <noreply(a)github.com>
date: 2019-06-01T11:00:15+03:00
summary:
bpo-37116: Use PEP 570 syntax for positional-only parameters. (GH-13700)
files:
M Doc/library/collections.rst
M Doc/library/contextlib.rst
M Doc/library/email.headerregistry.rst
M Doc/library/functools.rst
M Doc/library/inspect.rst
M Doc/library/operator.rst
M Doc/library/string.rst
M Doc/library/types.rst
M Doc/library/unittest.mock-examples.rst
M Doc/library/unittest.rst
M Doc/library/weakref.rst
M Doc/whatsnew/3.8.rst
M Lib/_collections_abc.py
M Lib/_py_abc.py
M Lib/_threading_local.py
M Lib/collections/__init__.py
M Lib/contextlib.py
M Lib/dataclasses.py
M Lib/functools.py
M Lib/idlelib/debugger_r.py
M Lib/idlelib/rpc.py
M Lib/inspect.py
M Lib/multiprocessing/dummy/__init__.py
M Lib/multiprocessing/managers.py
M Lib/multiprocessing/pool.py
M Lib/operator.py
M Lib/random.py
M Lib/string.py
M Lib/test/support/script_helper.py
M Lib/typing.py
M Lib/unittest/case.py
M Lib/unittest/mock.py
M Lib/unittest/test/test_runner.py
M Lib/weakref.py
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index ec921d79d0c4..90a3f4bea9a4 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -1140,7 +1140,7 @@ variants of :func:`functools.lru_cache`::
class LRU(OrderedDict):
'Limit size, evicting the least recently looked-up key when full'
- def __init__(self, maxsize=128, *args, **kwds):
+ def __init__(self, maxsize=128, /, *args, **kwds):
self.maxsize = maxsize
super().__init__(*args, **kwds)
diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst
index 017a87a5648c..73b24e5f251a 100644
--- a/Doc/library/contextlib.rst
+++ b/Doc/library/contextlib.rst
@@ -637,7 +637,7 @@ even further by means of a small helper class::
from contextlib import ExitStack
class Callback(ExitStack):
- def __init__(self, callback, *args, **kwds):
+ def __init__(self, callback, /, *args, **kwds):
super(Callback, self).__init__()
self.callback(callback, *args, **kwds)
diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst
index ce283c6b596c..c3ce90c2d6d9 100644
--- a/Doc/library/email.headerregistry.rst
+++ b/Doc/library/email.headerregistry.rst
@@ -107,7 +107,7 @@ headers.
method if it wishes to set additional attributes beyond those provided by
``BaseHeader`` itself. Such an ``init`` method should look like this::
- def init(self, *args, **kw):
+ def init(self, /, *args, **kw):
self._myattr = kw.pop('myattr')
super().init(*args, **kw)
diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst
index 8b8b1f80a622..654a3efa214b 100644
--- a/Doc/library/functools.rst
+++ b/Doc/library/functools.rst
@@ -221,7 +221,7 @@ The :mod:`functools` module defines the following functions:
Returning NotImplemented from the underlying comparison function for
unrecognised types is now supported.
-.. function:: partial(func, *args, **keywords)
+.. function:: partial(func, /, *args, **keywords)
Return a new :ref:`partial object<partial-objects>` which when called
will behave like *func* called with the positional arguments *args*
@@ -230,7 +230,7 @@ The :mod:`functools` module defines the following functions:
supplied, they extend and override *keywords*.
Roughly equivalent to::
- def partial(func, *args, **keywords):
+ def partial(func, /, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = {**keywords, **fkeywords}
return func(*args, *fargs, **newkeywords)
diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
index 1cc503a8e94b..2a71201a80b2 100644
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -1022,7 +1022,7 @@ Classes and functions
metatype is in use, cls will be the first element of the tuple.
-.. function:: getcallargs(func, *args, **kwds)
+.. function:: getcallargs(func, /, *args, **kwds)
Bind the *args* and *kwds* to the argument names of the Python function or
method *func*, as if it was called with them. For bound methods, bind also the
diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst
index 5d0ea7dfdd89..fa02bde84650 100644
--- a/Doc/library/operator.rst
+++ b/Doc/library/operator.rst
@@ -339,7 +339,7 @@ expect a function argument.
[('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]
-.. function:: methodcaller(name[, args...])
+.. function:: methodcaller(name, /, *args, **kwargs)
Return a callable object that calls the method *name* on its operand. If
additional arguments and/or keyword arguments are given, they will be given
@@ -352,7 +352,7 @@ expect a function argument.
Equivalent to::
- def methodcaller(name, *args, **kwargs):
+ def methodcaller(name, /, *args, **kwargs):
def caller(obj):
return getattr(obj, name)(*args, **kwargs)
return caller
diff --git a/Doc/library/string.rst b/Doc/library/string.rst
index c2f65224bc8d..288dde6b3fe4 100644
--- a/Doc/library/string.rst
+++ b/Doc/library/string.rst
@@ -88,7 +88,7 @@ implementation as the built-in :meth:`~str.format` method.
The :class:`Formatter` class has the following public methods:
- .. method:: format(format_string, *args, **kwargs)
+ .. method:: format(format_string, /, *args, **kwargs)
The primary API method. It takes a format string and
an arbitrary set of positional and keyword arguments.
@@ -720,7 +720,7 @@ these rules. The methods of :class:`Template` are:
The constructor takes a single argument which is the template string.
- .. method:: substitute(mapping, **kwds)
+ .. method:: substitute(mapping={}, /, **kwds)
Performs the template substitution, returning a new string. *mapping* is
any dictionary-like object with keys that match the placeholders in the
@@ -729,7 +729,7 @@ these rules. The methods of :class:`Template` are:
and there are duplicates, the placeholders from *kwds* take precedence.
- .. method:: safe_substitute(mapping, **kwds)
+ .. method:: safe_substitute(mapping={}, /, **kwds)
Like :meth:`substitute`, except that if placeholders are missing from
*mapping* and *kwds*, instead of raising a :exc:`KeyError` exception, the
diff --git a/Doc/library/types.rst b/Doc/library/types.rst
index 07c3a2e7f682..e629c2935f27 100644
--- a/Doc/library/types.rst
+++ b/Doc/library/types.rst
@@ -327,7 +327,7 @@ Additional Utility Classes and Functions
The type is roughly equivalent to the following code::
class SimpleNamespace:
- def __init__(self, **kwargs):
+ def __init__(self, /, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst
index 16690f349822..811f0fb1ce93 100644
--- a/Doc/library/unittest.mock-examples.rst
+++ b/Doc/library/unittest.mock-examples.rst
@@ -848,7 +848,7 @@ Here's an example implementation:
>>> from copy import deepcopy
>>> class CopyingMock(MagicMock):
- ... def __call__(self, *args, **kwargs):
+ ... def __call__(self, /, *args, **kwargs):
... args = deepcopy(args)
... kwargs = deepcopy(kwargs)
... return super(CopyingMock, self).__call__(*args, **kwargs)
@@ -1042,7 +1042,7 @@ that it takes arbitrary keyword arguments (``**kwargs``) which are then passed
onto the mock constructor:
>>> class Subclass(MagicMock):
- ... def _get_child_mock(self, **kwargs):
+ ... def _get_child_mock(self, /, **kwargs):
... return MagicMock(**kwargs)
...
>>> mymock = Subclass()
diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
index 54a9f2c6f735..5ec4b40856ae 100644
--- a/Doc/library/unittest.rst
+++ b/Doc/library/unittest.rst
@@ -1456,7 +1456,7 @@ Test cases
.. versionadded:: 3.1
- .. classmethod:: addClassCleanup(function, *args, **kwargs)
+ .. classmethod:: addClassCleanup(function, /, *args, **kwargs)
Add a function to be called after :meth:`tearDownClass` to cleanup
resources used during the test class. Functions will be called in reverse
@@ -2313,7 +2313,7 @@ To add cleanup code that must be run even in the case of an exception, use
``addModuleCleanup``:
-.. function:: addModuleCleanup(function, *args, **kwargs)
+.. function:: addModuleCleanup(function, /, *args, **kwargs)
Add a function to be called after :func:`tearDownModule` to cleanup
resources used during the test class. Functions will be called in reverse
diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst
index 80a908bbd83b..a28d71060f38 100644
--- a/Doc/library/weakref.rst
+++ b/Doc/library/weakref.rst
@@ -396,7 +396,7 @@ the referent is accessed::
import weakref
class ExtendedRef(weakref.ref):
- def __init__(self, ob, callback=None, **annotations):
+ def __init__(self, ob, callback=None, /, **annotations):
super(ExtendedRef, self).__init__(ob, callback)
self.__counter = 0
for k, v in annotations.items():
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 76d00938dbec..bc7c9ef37442 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -941,8 +941,7 @@ Deprecated
:meth:`profile.Profile.runcall`, :meth:`cProfile.Profile.runcall`,
:meth:`bdb.Bdb.runcall`, :meth:`trace.Trace.runfunc` and
:func:`curses.wrapper`.
- - *function* in :func:`unittest.addModuleCleanup` and
- :meth:`unittest.TestCase.addCleanup`.
+ - *function* in :meth:`unittest.TestCase.addCleanup`.
- *fn* in the :meth:`~concurrent.futures.Executor.submit` method of
:class:`concurrent.futures.ThreadPoolExecutor` and
:class:`concurrent.futures.ProcessPoolExecutor`.
diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
index c363987970b4..2b2ddba170e1 100644
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -821,30 +821,21 @@ def clear(self):
except KeyError:
pass
- def update(*args, **kwds):
+ def update(self, other=(), /, **kwds):
''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F.
If E present and has a .keys() method, does: for k in E: D[k] = E[k]
If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v
In either case, this is followed by: for k, v in F.items(): D[k] = v
'''
- if not args:
- raise TypeError("descriptor 'update' of 'MutableMapping' object "
- "needs an argument")
- self, *args = args
- if len(args) > 1:
- raise TypeError('update expected at most 1 arguments, got %d' %
- len(args))
- if args:
- other = args[0]
- if isinstance(other, Mapping):
- for key in other:
- self[key] = other[key]
- elif hasattr(other, "keys"):
- for key in other.keys():
- self[key] = other[key]
- else:
- for key, value in other:
- self[key] = value
+ if isinstance(other, Mapping):
+ for key in other:
+ self[key] = other[key]
+ elif hasattr(other, "keys"):
+ for key in other.keys():
+ self[key] = other[key]
+ else:
+ for key, value in other:
+ self[key] = value
for key, value in kwds.items():
self[key] = value
diff --git a/Lib/_py_abc.py b/Lib/_py_abc.py
index 3c3aa8e3d61b..c870ae9048b4 100644
--- a/Lib/_py_abc.py
+++ b/Lib/_py_abc.py
@@ -32,7 +32,7 @@ class ABCMeta(type):
# external code.
_abc_invalidation_counter = 0
- def __new__(mcls, name, bases, namespace, **kwargs):
+ def __new__(mcls, name, bases, namespace, /, **kwargs):
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
# Compute set of abstract method names
abstracts = {name
diff --git a/Lib/_threading_local.py b/Lib/_threading_local.py
index 245bd0ac91b7..b006d76c4e23 100644
--- a/Lib/_threading_local.py
+++ b/Lib/_threading_local.py
@@ -56,7 +56,7 @@
>>> class MyLocal(local):
... number = 2
- ... def __init__(self, **kw):
+ ... def __init__(self, /, **kw):
... self.__dict__.update(kw)
... def squared(self):
... return self.number ** 2
@@ -204,7 +204,7 @@ def _patch(self):
class local:
__slots__ = '_local__impl', '__dict__'
- def __new__(cls, *args, **kw):
+ def __new__(cls, /, *args, **kw):
if (args or kw) and (cls.__init__ is object.__init__):
raise TypeError("Initialization arguments are not supported")
self = object.__new__(cls)
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index 5b740d84c275..e9999e27d5f5 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -93,16 +93,10 @@ class OrderedDict(dict):
# Individual links are kept alive by the hard reference in self.__map.
# Those hard references disappear when a key is deleted from an OrderedDict.
- def __init__(*args, **kwds):
+ def __init__(self, other=(), /, **kwds):
'''Initialize an ordered dictionary. The signature is the same as
regular dictionaries. Keyword argument order is preserved.
'''
- if not args:
- raise TypeError("descriptor '__init__' of 'OrderedDict' object "
- "needs an argument")
- self, *args = args
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__root
except AttributeError:
@@ -110,7 +104,7 @@ def __init__(*args, **kwds):
self.__root = root = _proxy(self.__hardroot)
root.prev = root.next = root
self.__map = {}
- self.__update(*args, **kwds)
+ self.__update(other, **kwds)
def __setitem__(self, key, value,
dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):
@@ -413,8 +407,8 @@ def _make(cls, iterable):
_make.__func__.__doc__ = (f'Make a new {typename} object from a sequence '
'or iterable')
- def _replace(_self, **kwds):
- result = _self._make(_map(kwds.pop, field_names, _self))
+ def _replace(self, /, **kwds):
+ result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
return result
@@ -543,7 +537,7 @@ class Counter(dict):
# http://code.activestate.com/recipes/259174/
# Knuth, TAOCP Vol. II section 4.6.3
- def __init__(*args, **kwds):
+ def __init__(self, iterable=None, /, **kwds):
'''Create a new, empty Counter object. And if given, count elements
from an input iterable. Or, initialize the count from another mapping
of elements to their counts.
@@ -554,14 +548,8 @@ def __init__(*args, **kwds):
>>> c = Counter(a=4, b=2) # a new counter from keyword args
'''
- if not args:
- raise TypeError("descriptor '__init__' of 'Counter' object "
- "needs an argument")
- self, *args = args
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
super(Counter, self).__init__()
- self.update(*args, **kwds)
+ self.update(iterable, **kwds)
def __missing__(self, key):
'The count of elements not in the Counter is zero.'
@@ -617,7 +605,7 @@ def fromkeys(cls, iterable, v=None):
raise NotImplementedError(
'Counter.fromkeys() is undefined. Use Counter(iterable) instead.')
- def update(*args, **kwds):
+ def update(self, iterable=None, /, **kwds):
'''Like dict.update() but add counts instead of replacing them.
Source can be an iterable, a dictionary, or another Counter instance.
@@ -637,13 +625,6 @@ def update(*args, **kwds):
# contexts. Instead, we implement straight-addition. Both the inputs
# and outputs are allowed to contain zero and negative counts.
- if not args:
- raise TypeError("descriptor 'update' of 'Counter' object "
- "needs an argument")
- self, *args = args
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
- iterable = args[0] if args else None
if iterable is not None:
if isinstance(iterable, _collections_abc.Mapping):
if self:
@@ -657,7 +638,7 @@ def update(*args, **kwds):
if kwds:
self.update(kwds)
- def subtract(*args, **kwds):
+ def subtract(self, iterable=None, /, **kwds):
'''Like dict.update() but subtracts counts instead of replacing them.
Counts can be reduced below zero. Both the inputs and outputs are
allowed to contain zero and negative counts.
@@ -673,13 +654,6 @@ def subtract(*args, **kwds):
-1
'''
- if not args:
- raise TypeError("descriptor 'subtract' of 'Counter' object "
- "needs an argument")
- self, *args = args
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
- iterable = args[0] if args else None
if iterable is not None:
self_get = self.get
if isinstance(iterable, _collections_abc.Mapping):
@@ -1141,7 +1115,7 @@ def copy(self): return self.__class__(self)
def count(self, item): return self.data.count(item)
def index(self, item, *args): return self.data.index(item, *args)
def reverse(self): self.data.reverse()
- def sort(self, *args, **kwds): self.data.sort(*args, **kwds)
+ def sort(self, /, *args, **kwds): self.data.sort(*args, **kwds)
def extend(self, other):
if isinstance(other, UserList):
self.data.extend(other.data)
@@ -1240,7 +1214,7 @@ def find(self, sub, start=0, end=_sys.maxsize):
if isinstance(sub, UserString):
sub = sub.data
return self.data.find(sub, start, end)
- def format(self, *args, **kwds):
+ def format(self, /, *args, **kwds):
return self.data.format(*args, **kwds)
def format_map(self, mapping):
return self.data.format_map(mapping)
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index de989a001c6d..94dc2bfed06c 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -377,8 +377,7 @@ def _create_exit_wrapper(cm, cm_exit):
return MethodType(cm_exit, cm)
@staticmethod
- def _create_cb_wrapper(*args, **kwds):
- callback, *args = args
+ def _create_cb_wrapper(callback, /, *args, **kwds):
def _exit_wrapper(exc_type, exc, tb):
callback(*args, **kwds)
return _exit_wrapper
@@ -553,8 +552,7 @@ def _create_async_exit_wrapper(cm, cm_exit):
return MethodType(cm_exit, cm)
@staticmethod
- def _create_async_cb_wrapper(*args, **kwds):
- callback, *args = args
+ def _create_async_cb_wrapper(callback, /, *args, **kwds):
async def _exit_wrapper(exc_type, exc, tb):
await callback(*args, **kwds)
return _exit_wrapper
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py
index 325b822d9f06..75113f123b3a 100644
--- a/Lib/dataclasses.py
+++ b/Lib/dataclasses.py
@@ -962,10 +962,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
return cls
-# _cls should never be specified by keyword, so start it with an
-# underscore. The presence of _cls is used to detect if this
-# decorator is being called with parameters or not.
-def dataclass(_cls=None, *, init=True, repr=True, eq=True, order=False,
+def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False,
unsafe_hash=False, frozen=False):
"""Returns the same class as was passed in, with dunder methods
added based on the fields defined in the class.
@@ -983,12 +980,12 @@ def wrap(cls):
return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
# See if we're being called as @dataclass or @dataclass().
- if _cls is None:
+ if cls is None:
# We're called with parens.
return wrap
# We're called as @dataclass without parens.
- return wrap(_cls)
+ return wrap(cls)
def fields(class_or_instance):
diff --git a/Lib/functools.py b/Lib/functools.py
index 30964a6fe3d8..64d120182bb0 100644
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -273,15 +273,9 @@ class partial:
__slots__ = "func", "args", "keywords", "__dict__", "__weakref__"
- def __new__(*args, **keywords):
- if not args:
- raise TypeError("descriptor '__new__' of partial needs an argument")
- if len(args) < 2:
- raise TypeError("type 'partial' takes at least one argument")
- cls, func, *args = args
+ def __new__(cls, func, /, *args, **keywords):
if not callable(func):
raise TypeError("the first argument must be callable")
- args = tuple(args)
if hasattr(func, "func"):
args = func.args + args
@@ -295,10 +289,7 @@ def __new__(*args, **keywords):
self.keywords = keywords
return self
- def __call__(*args, **keywords):
- if not args:
- raise TypeError("descriptor '__call__' of partial needs an argument")
- self, *args = args
+ def __call__(self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(*self.args, *args, **keywords)
@@ -402,8 +393,7 @@ def __repr__(self):
keywords=keywords)
def _make_unbound_method(self):
- def _method(*args, **keywords):
- cls_or_self, *args = args
+ def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
_method.__isabstractmethod__ = self.__isabstractmethod__
diff --git a/Lib/idlelib/debugger_r.py b/Lib/idlelib/debugger_r.py
index 0e6dcfbd12c2..9dcfc56414c0 100644
--- a/Lib/idlelib/debugger_r.py
+++ b/Lib/idlelib/debugger_r.py
@@ -299,7 +299,7 @@ def __init__(self, conn, shell, oid):
self.conn = conn
self.shell = shell
- def call(self, methodname, *args, **kwargs):
+ def call(self, methodname, /, *args, **kwargs):
##print("*** IdbProxy.call %s %s %s" % (methodname, args, kwargs))
value = self.conn.remotecall(self.oid, methodname, args, kwargs)
##print("*** IdbProxy.call %s returns %r" % (methodname, value))
diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py
index f035bde4a0a0..aa8cbd36c479 100644
--- a/Lib/idlelib/rpc.py
+++ b/Lib/idlelib/rpc.py
@@ -603,7 +603,7 @@ def __init__(self, sockio, oid, name):
self.oid = oid
self.name = name
- def __call__(self, *args, **kwargs):
+ def __call__(self, /, *args, **kwargs):
value = self.sockio.remotecall(self.oid, self.name, args, kwargs)
return value
diff --git a/Lib/inspect.py b/Lib/inspect.py
index a4f28f755705..ca81a24f0641 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1329,14 +1329,12 @@ def _too_many(f_name, args, kwonly, varargs, defcount, given, values):
(f_name, sig, "s" if plural else "", given, kwonly_sig,
"was" if given == 1 and not kwonly_given else "were"))
-def getcallargs(*func_and_positional, **named):
+def getcallargs(func, /, *positional, **named):
"""Get the mapping of arguments to values.
A dict is returned, with keys the function argument names (including the
names of the * and ** arguments, if any), and values the respective bound
values from 'positional' and 'named'."""
- func = func_and_positional[0]
- positional = func_and_positional[1:]
spec = getfullargspec(func)
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec
f_name = func.__name__
@@ -3027,19 +3025,19 @@ def _bind(self, args, kwargs, *, partial=False):
return self._bound_arguments_cls(self, arguments)
- def bind(*args, **kwargs):
+ def bind(self, /, *args, **kwargs):
"""Get a BoundArguments object, that maps the passed `args`
and `kwargs` to the function's signature. Raises `TypeError`
if the passed arguments can not be bound.
"""
- return args[0]._bind(args[1:], kwargs)
+ return self._bind(args, kwargs)
- def bind_partial(*args, **kwargs):
+ def bind_partial(self, /, *args, **kwargs):
"""Get a BoundArguments object, that partially maps the
passed `args` and `kwargs` to the function's signature.
Raises `TypeError` if the passed arguments can not be bound.
"""
- return args[0]._bind(args[1:], kwargs, partial=True)
+ return self._bind(args, kwargs, partial=True)
def __reduce__(self):
return (type(self),
diff --git a/Lib/multiprocessing/dummy/__init__.py b/Lib/multiprocessing/dummy/__init__.py
index 403f5e5198e4..6a1468609e34 100644
--- a/Lib/multiprocessing/dummy/__init__.py
+++ b/Lib/multiprocessing/dummy/__init__.py
@@ -80,7 +80,7 @@ def freeze_support():
#
class Namespace(object):
- def __init__(self, **kwds):
+ def __init__(self, /, **kwds):
self.__dict__.update(kwds)
def __repr__(self):
items = list(self.__dict__.items())
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
index 514152298b09..7e1818bb0996 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -615,13 +615,10 @@ def _run_server(cls, registry, address, authkey, serializer, writer,
util.info('manager serving at %r', server.address)
server.serve_forever()
- def _create(*args, **kwds):
+ def _create(self, typeid, /, *args, **kwds):
'''
Create a new shared object; return the token and exposed tuple
'''
- self, typeid, *args = args
- args = tuple(args)
-
assert self._state.value == State.STARTED, 'server not yet started'
conn = self._Client(self._address, authkey=self._authkey)
try:
@@ -738,7 +735,7 @@ def register(cls, typeid, callable=None, proxytype=None, exposed=None,
)
if create_method:
- def temp(self, *args, **kwds):
+ def temp(self, /, *args, **kwds):
util.debug('requesting creation of a shared %r object', typeid)
token, exp = self._create(typeid, *args, **kwds)
proxy = proxytype(
@@ -978,7 +975,7 @@ def MakeProxyType(name, exposed, _cache={}):
dic = {}
for meth in exposed:
- exec('''def %s(self, *args, **kwds):
+ exec('''def %s(self, /, *args, **kwds):
return self._callmethod(%r, args, kwds)''' % (meth, meth), dic)
ProxyType = type(name, (BaseProxy,), dic)
@@ -1017,7 +1014,7 @@ def AutoProxy(token, serializer, manager=None, authkey=None,
#
class Namespace(object):
- def __init__(self, **kwds):
+ def __init__(self, /, **kwds):
self.__dict__.update(kwds)
def __repr__(self):
items = list(self.__dict__.items())
diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py
index 665ca067fa07..b223d6aa724b 100644
--- a/Lib/multiprocessing/pool.py
+++ b/Lib/multiprocessing/pool.py
@@ -154,7 +154,7 @@ class _PoolCache(dict):
notification is done by the use of a queue that is provided when
instantiating the cache.
"""
- def __init__(self, *args, notifier=None, **kwds):
+ def __init__(self, /, *args, notifier=None, **kwds):
self.notifier = notifier
super().__init__(*args, **kwds)
diff --git a/Lib/operator.py b/Lib/operator.py
index 0e2e53efc69a..fb58851fa6ef 100644
--- a/Lib/operator.py
+++ b/Lib/operator.py
@@ -302,15 +302,11 @@ class methodcaller:
"""
__slots__ = ('_name', '_args', '_kwargs')
- def __init__(*args, **kwargs):
- if len(args) < 2:
- msg = "methodcaller needs at least one argument, the method name"
- raise TypeError(msg)
- self = args[0]
- self._name = args[1]
+ def __init__(self, name, /, *args, **kwargs):
+ self._name = name
if not isinstance(self._name, str):
raise TypeError('method name must be a string')
- self._args = args[2:]
+ self._args = args
self._kwargs = kwargs
def __call__(self, obj):
diff --git a/Lib/random.py b/Lib/random.py
index 53981f3e4f89..365a01957203 100644
--- a/Lib/random.py
+++ b/Lib/random.py
@@ -100,7 +100,7 @@ def __init__(self, x=None):
self.seed(x)
self.gauss_next = None
- def __init_subclass__(cls, **kwargs):
+ def __init_subclass__(cls, /, **kwargs):
"""Control how subclasses generate random integers.
The algorithm a subclass can use depends on the random() and/or
diff --git a/Lib/string.py b/Lib/string.py
index b9d6f5eb5675..b423ff5dc6f6 100644
--- a/Lib/string.py
+++ b/Lib/string.py
@@ -52,6 +52,8 @@ def capwords(s, sep=None):
import re as _re
from collections import ChainMap as _ChainMap
+_sentinel_dict = {}
+
class _TemplateMetaclass(type):
pattern = r"""
%(delim)s(?:
@@ -104,19 +106,11 @@ def _invalid(self, mo):
raise ValueError('Invalid placeholder in string: line %d, col %d' %
(lineno, colno))
- def substitute(*args, **kws):
- if not args:
- raise TypeError("descriptor 'substitute' of 'Template' object "
- "needs an argument")
- self, *args = args # allow the "self" keyword be passed
- if len(args) > 1:
- raise TypeError('Too many positional arguments')
- if not args:
+ def substitute(self, mapping=_sentinel_dict, /, **kws):
+ if mapping is _sentinel_dict:
mapping = kws
elif kws:
- mapping = _ChainMap(kws, args[0])
- else:
- mapping = args[0]
+ mapping = _ChainMap(kws, mapping)
# Helper function for .sub()
def convert(mo):
# Check the most common path first.
@@ -131,19 +125,11 @@ def convert(mo):
self.pattern)
return self.pattern.sub(convert, self.template)
- def safe_substitute(*args, **kws):
- if not args:
- raise TypeError("descriptor 'safe_substitute' of 'Template' object "
- "needs an argument")
- self, *args = args # allow the "self" keyword be passed
- if len(args) > 1:
- raise TypeError('Too many positional arguments')
- if not args:
+ def safe_substitute(self, mapping=_sentinel_dict, /, **kws):
+ if mapping is _sentinel_dict:
mapping = kws
elif kws:
- mapping = _ChainMap(kws, args[0])
- else:
- mapping = args[0]
+ mapping = _ChainMap(kws, mapping)
# Helper function for .sub()
def convert(mo):
named = mo.group('named') or mo.group('braced')
@@ -173,16 +159,7 @@ def convert(mo):
# The field name parser is implemented in _string.formatter_field_name_split
class Formatter:
- def format(*args, **kwargs):
- if not args:
- raise TypeError("descriptor 'format' of 'Formatter' object "
- "needs an argument")
- self, *args = args # allow the "self" keyword be passed
- try:
- format_string, *args = args # allow the "format_string" keyword be passed
- except ValueError:
- raise TypeError("format() missing 1 required positional "
- "argument: 'format_string'") from None
+ def format(self, format_string, /, *args, **kwargs):
return self.vformat(format_string, args, kwargs)
def vformat(self, format_string, args, kwargs):
diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py
index 27a47f2c4e66..83519988e394 100644
--- a/Lib/test/support/script_helper.py
+++ b/Lib/test/support/script_helper.py
@@ -137,7 +137,7 @@ def run_python_until_end(*args, **env_vars):
err = strip_python_stderr(err)
return _PythonRunResult(rc, out, err), cmd_line
-def _assert_python(expected_success, *args, **env_vars):
+def _assert_python(expected_success, /, *args, **env_vars):
res, cmd_line = run_python_until_end(*args, **env_vars)
if (res.rc and expected_success) or (not res.rc and not expected_success):
res.fail(cmd_line)
diff --git a/Lib/typing.py b/Lib/typing.py
index 16ccfad049f4..5f1a0ad3d637 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -283,7 +283,7 @@ class _Final:
__slots__ = ('__weakref__',)
- def __init_subclass__(self, *args, **kwds):
+ def __init_subclass__(self, /, *args, **kwds):
if '_root' not in kwds:
raise TypeError("Cannot subclass special typing classes")
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index 7b1e86941315..b363c6351007 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -86,23 +86,10 @@ def _id(obj):
_module_cleanups = []
-def addModuleCleanup(*args, **kwargs):
+def addModuleCleanup(function, /, *args, **kwargs):
"""Same as addCleanup, except the cleanup items are called even if
setUpModule fails (unlike tearDownModule)."""
- if args:
- function, *args = args
- elif 'function' in kwargs:
- function = kwargs.pop('function')
- import warnings
- warnings.warn("Passing 'function' as keyword argument is deprecated",
- DeprecationWarning, stacklevel=2)
- else:
- raise TypeError('addModuleCleanup expected at least 1 positional '
- 'argument, got %d' % (len(args)-1))
- args = tuple(args)
-
_module_cleanups.append((function, args, kwargs))
-addModuleCleanup.__text_signature__ = '(function, /, *args, **kwargs)'
def doModuleCleanups():
@@ -501,22 +488,11 @@ def addCleanup(*args, **kwargs):
self._cleanups.append((function, args, kwargs))
addCleanup.__text_signature__ = '($self, function, /, *args, **kwargs)'
- def addClassCleanup(*args, **kwargs):
+ @classmethod
+ def addClassCleanup(cls, function, /, *args, **kwargs):
"""Same as addCleanup, except the cleanup items are called even if
setUpClass fails (unlike tearDownClass)."""
- if len(args) >= 2:
- cls, function, *args = args
- elif not args:
- raise TypeError("descriptor 'addClassCleanup' of 'TestCase' object "
- "needs an argument")
- else:
- raise TypeError('addClassCleanup expected at least 1 positional '
- 'argument, got %d' % (len(args)-1))
- args = tuple(args)
-
cls._class_cleanups.append((function, args, kwargs))
- addClassCleanup.__text_signature__ = '($cls, function, /, *args, **kwargs)'
- addClassCleanup = classmethod(addClassCleanup)
def setUp(self):
"Hook method for setting up the test fixture before exercising it."
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index be96194793ef..c2802726d75d 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -106,7 +106,7 @@ def _check_signature(func, mock, skipfirst, instance=False):
if sig is None:
return
func, sig = sig
- def checksig(_mock_self, *args, **kwargs):
+ def checksig(self, /, *args, **kwargs):
sig.bind(*args, **kwargs)
_copy_func_details(func, checksig)
type(mock)._mock_check_sig = checksig
@@ -243,7 +243,7 @@ def _setup_async_mock(mock):
# Mock is not configured yet so the attributes are set
# to a function and then the corresponding mock helper function
# is called when the helper is accessed similar to _setup_func.
- def wrapper(attr, *args, **kwargs):
+ def wrapper(attr, /, *args, **kwargs):
return getattr(mock.mock, attr)(*args, **kwargs)
for attribute in ('assert_awaited',
@@ -387,7 +387,7 @@ def __next__(self):
class Base(object):
_mock_return_value = DEFAULT
_mock_side_effect = None
- def __init__(self, *args, **kwargs):
+ def __init__(self, /, *args, **kwargs):
pass
@@ -395,7 +395,7 @@ def __init__(self, *args, **kwargs):
class NonCallableMock(Base):
"""A non-callable version of `Mock`"""
- def __new__(cls, *args, **kw):
+ def __new__(cls, /, *args, **kw):
# every instance has its own class
# so we can create magic methods on the
# class without stomping on other mocks
@@ -602,7 +602,7 @@ def reset_mock(self, visited=None,*, return_value=False, side_effect=False):
ret.reset_mock(visited)
- def configure_mock(self, **kwargs):
+ def configure_mock(self, /, **kwargs):
"""Set attributes on the mock through keyword arguments.
Attributes plus return values and side effects can be set on child
@@ -820,10 +820,9 @@ def _call_matcher(self, _call):
else:
return _call
- def assert_not_called(_mock_self):
+ def assert_not_called(self):
"""assert that the mock was never called.
"""
- self = _mock_self
if self.call_count != 0:
msg = ("Expected '%s' to not have been called. Called %s times.%s"
% (self._mock_name or 'mock',
@@ -831,19 +830,17 @@ def assert_not_called(_mock_self):
self._calls_repr()))
raise AssertionError(msg)
- def assert_called(_mock_self):
+ def assert_called(self):
"""assert that the mock was called at least once
"""
- self = _mock_self
if self.call_count == 0:
msg = ("Expected '%s' to have been called." %
self._mock_name or 'mock')
raise AssertionError(msg)
- def assert_called_once(_mock_self):
+ def assert_called_once(self):
"""assert that the mock was called only once.
"""
- self = _mock_self
if not self.call_count == 1:
msg = ("Expected '%s' to have been called once. Called %s times.%s"
% (self._mock_name or 'mock',
@@ -851,12 +848,11 @@ def assert_called_once(_mock_self):
self._calls_repr()))
raise AssertionError(msg)
- def assert_called_with(_mock_self, *args, **kwargs):
+ def assert_called_with(self, /, *args, **kwargs):
"""assert that the mock was called with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
- self = _mock_self
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
@@ -874,10 +870,9 @@ def _error_message():
raise AssertionError(_error_message()) from cause
- def assert_called_once_with(_mock_self, *args, **kwargs):
+ def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
- self = _mock_self
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
@@ -924,7 +919,7 @@ def assert_has_calls(self, calls, any_order=False):
) from cause
- def assert_any_call(self, *args, **kwargs):
+ def assert_any_call(self, /, *args, **kwargs):
"""assert the mock has been called with the specified arguments.
The assert passes if the mock has *ever* been called, unlike
@@ -940,7 +935,7 @@ def assert_any_call(self, *args, **kwargs):
) from cause
- def _get_child_mock(self, **kw):
+ def _get_child_mock(self, /, **kw):
"""Create the child mocks for attributes and return value.
By default child mocks will be the same type as the parent.
Subclasses of Mock may want to override this to customize the way
@@ -1016,20 +1011,19 @@ def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
self.side_effect = side_effect
- def _mock_check_sig(self, *args, **kwargs):
+ def _mock_check_sig(self, /, *args, **kwargs):
# stub method that can be replaced with one with a specific signature
pass
- def __call__(_mock_self, *args, **kwargs):
+ def __call__(self, /, *args, **kwargs):
# can't use self in-case a function / method we are mocking uses self
# in the signature
- _mock_self._mock_check_sig(*args, **kwargs)
- return _mock_self._mock_call(*args, **kwargs)
+ self._mock_check_sig(*args, **kwargs)
+ return self._mock_call(*args, **kwargs)
- def _mock_call(_mock_self, *args, **kwargs):
- self = _mock_self
+ def _mock_call(self, /, *args, **kwargs):
self.called = True
self.call_count += 1
@@ -1840,7 +1834,7 @@ def _patch_stopall():
def _get_method(name, func):
"Turns a callable object (like a mock) into a real function"
- def method(self, *args, **kw):
+ def method(self, /, *args, **kw):
return func(self, *args, **kw)
method.__name__ = name
return method
@@ -1954,7 +1948,7 @@ def _set_return_value(mock, method, name):
class MagicMixin(object):
- def __init__(self, *args, **kw):
+ def __init__(self, /, *args, **kw):
self._mock_set_magics() # make magic work for kwargs in init
_safe_super(MagicMixin, self).__init__(*args, **kw)
self._mock_set_magics() # fix magic broken by upper level init
@@ -1996,7 +1990,7 @@ def mock_add_spec(self, spec, spec_set=False):
class AsyncMagicMixin:
- def __init__(self, *args, **kw):
+ def __init__(self, /, *args, **kw):
self._mock_set_async_magics() # make magic work for kwargs in init
_safe_super(AsyncMagicMixin, self).__init__(*args, **kw)
self._mock_set_async_magics() # fix magic broken by upper level init
@@ -2067,7 +2061,7 @@ class AsyncMockMixin(Base):
await_args = _delegating_property('await_args')
await_args_list = _delegating_property('await_args_list')
- def __init__(self, *args, **kwargs):
+ def __init__(self, /, *args, **kwargs):
super().__init__(*args, **kwargs)
# asyncio.iscoroutinefunction() checks _is_coroutine property to say if an
# object is a coroutine. Without this check it looks to see if it is a
@@ -2084,8 +2078,7 @@ def __init__(self, *args, **kwargs):
code_mock.co_flags = inspect.CO_COROUTINE
self.__dict__['__code__'] = code_mock
- async def _mock_call(_mock_self, *args, **kwargs):
- self = _mock_self
+ async def _mock_call(self, /, *args, **kwargs):
try:
result = super()._mock_call(*args, **kwargs)
except (BaseException, StopIteration) as e:
@@ -2110,30 +2103,27 @@ def __init__(self, *args, **kwargs):
return await proxy()
- def assert_awaited(_mock_self):
+ def assert_awaited(self):
"""
Assert that the mock was awaited at least once.
"""
- self = _mock_self
if self.await_count == 0:
msg = f"Expected {self._mock_name or 'mock'} to have been awaited."
raise AssertionError(msg)
- def assert_awaited_once(_mock_self):
+ def assert_awaited_once(self):
"""
Assert that the mock was awaited exactly once.
"""
- self = _mock_self
if not self.await_count == 1:
msg = (f"Expected {self._mock_name or 'mock'} to have been awaited once."
f" Awaited {self.await_count} times.")
raise AssertionError(msg)
- def assert_awaited_with(_mock_self, *args, **kwargs):
+ def assert_awaited_with(self, /, *args, **kwargs):
"""
Assert that the last await was with the specified arguments.
"""
- self = _mock_self
if self.await_args is None:
expected = self._format_mock_call_signature(args, kwargs)
raise AssertionError(f'Expected await: {expected}\nNot awaited')
@@ -2148,23 +2138,21 @@ def _error_message():
cause = expected if isinstance(expected, Exception) else None
raise AssertionError(_error_message()) from cause
- def assert_awaited_once_with(_mock_self, *args, **kwargs):
+ def assert_awaited_once_with(self, /, *args, **kwargs):
"""
Assert that the mock was awaited exactly once and with the specified
arguments.
"""
- self = _mock_self
if not self.await_count == 1:
msg = (f"Expected {self._mock_name or 'mock'} to have been awaited once."
f" Awaited {self.await_count} times.")
raise AssertionError(msg)
return self.assert_awaited_with(*args, **kwargs)
- def assert_any_await(_mock_self, *args, **kwargs):
+ def assert_any_await(self, /, *args, **kwargs):
"""
Assert the mock has ever been awaited with the specified arguments.
"""
- self = _mock_self
expected = self._call_matcher((args, kwargs))
actual = [self._call_matcher(c) for c in self.await_args_list]
if expected not in actual:
@@ -2174,7 +2162,7 @@ def assert_any_await(_mock_self, *args, **kwargs):
'%s await not found' % expected_string
) from cause
- def assert_has_awaits(_mock_self, calls, any_order=False):
+ def assert_has_awaits(self, calls, any_order=False):
"""
Assert the mock has been awaited with the specified calls.
The :attr:`await_args_list` list is checked for the awaits.
@@ -2186,7 +2174,6 @@ def assert_has_awaits(_mock_self, calls, any_order=False):
If `any_order` is True then the awaits can be in any order, but
they must all appear in :attr:`await_args_list`.
"""
- self = _mock_self
expected = [self._call_matcher(c) for c in calls]
cause = expected if isinstance(expected, Exception) else None
all_awaits = _CallList(self._call_matcher(c) for c in self.await_args_list)
@@ -2211,17 +2198,16 @@ def assert_has_awaits(_mock_self, calls, any_order=False):
'%r not all found in await list' % (tuple(not_found),)
) from cause
- def assert_not_awaited(_mock_self):
+ def assert_not_awaited(self):
"""
Assert that the mock was never awaited.
"""
- self = _mock_self
if self.await_count != 0:
msg = (f"Expected {self._mock_name or 'mock'} to not have been awaited."
f" Awaited {self.await_count} times.")
raise AssertionError(msg)
- def reset_mock(self, *args, **kwargs):
+ def reset_mock(self, /, *args, **kwargs):
"""
See :func:`.Mock.reset_mock()`
"""
@@ -2424,7 +2410,7 @@ def __eq__(self, other):
__ne__ = object.__ne__
- def __call__(self, *args, **kwargs):
+ def __call__(self, /, *args, **kwargs):
if self._mock_name is None:
return _Call(('', args, kwargs), name='()')
@@ -2439,10 +2425,10 @@ def __getattr__(self, attr):
return _Call(name=name, parent=self, from_kall=False)
- def count(self, *args, **kwargs):
+ def count(self, /, *args, **kwargs):
return self.__getattr__('count')(*args, **kwargs)
- def index(self, *args, **kwargs):
+ def index(self, /, *args, **kwargs):
return self.__getattr__('index')(*args, **kwargs)
def _get_call_arguments(self):
@@ -2778,7 +2764,7 @@ class PropertyMock(Mock):
Fetching a `PropertyMock` instance from an object calls the mock, with
no args. Setting it calls the mock with the value being set.
"""
- def _get_child_mock(self, **kwargs):
+ def _get_child_mock(self, /, **kwargs):
return MagicMock(**kwargs)
def __get__(self, obj, obj_type):
diff --git a/Lib/unittest/test/test_runner.py b/Lib/unittest/test/test_runner.py
index 443b689dbea0..7d36340741f4 100644
--- a/Lib/unittest/test/test_runner.py
+++ b/Lib/unittest/test/test_runner.py
@@ -410,14 +410,13 @@ def cleanup(*args, **kwargs):
class Module(object):
unittest.addModuleCleanup(cleanup, 1, 2, function='hello')
- with self.assertWarns(DeprecationWarning):
+ with self.assertRaises(TypeError):
unittest.addModuleCleanup(function=cleanup, arg='hello')
with self.assertRaises(TypeError):
unittest.addModuleCleanup()
unittest.case.doModuleCleanups()
self.assertEqual(cleanups,
- [((), {'arg': 'hello'}),
- ((1, 2), {'function': 'hello'})])
+ [((1, 2), {'function': 'hello'})])
def test_run_module_cleanUp(self):
blowUp = True
diff --git a/Lib/weakref.py b/Lib/weakref.py
index 1eeb7b0a0b44..8d71af653b7e 100644
--- a/Lib/weakref.py
+++ b/Lib/weakref.py
@@ -99,13 +99,7 @@ class WeakValueDictionary(_collections_abc.MutableMapping):
# objects are unwrapped on the way out, and we always wrap on the
# way in).
- def __init__(*args, **kw):
- if not args:
- raise TypeError("descriptor '__init__' of 'WeakValueDictionary' "
- "object needs an argument")
- self, *args = args
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ def __init__(self, other=(), /, **kw):
def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
self = selfref()
if self is not None:
@@ -120,7 +114,7 @@ def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
self._pending_removals = []
self._iterating = set()
self.data = d = {}
- self.update(*args, **kw)
+ self.update(other, **kw)
def _commit_removals(self):
l = self._pending_removals
@@ -287,24 +281,17 @@ def setdefault(self, key, default=None):
else:
return o
- def update(*args, **kwargs):
- if not args:
- raise TypeError("descriptor 'update' of 'WeakValueDictionary' "
- "object needs an argument")
- self, *args = args
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
- dict = args[0] if args else None
+ def update(self, other=None, /, **kwargs):
if self._pending_removals:
self._commit_removals()
d = self.data
- if dict is not None:
- if not hasattr(dict, "items"):
- dict = type({})(dict)
- for key, o in dict.items():
+ if other is not None:
+ if not hasattr(other, "items"):
+ other = dict(other)
+ for key, o in other.items():
d[key] = KeyedRef(o, self._remove, key)
- if len(kwargs):
- self.update(kwargs)
+ for key, o in kwargs.items():
+ d[key] = KeyedRef(o, self._remove, key)
def valuerefs(self):
"""Return a list of weak references to the values.
@@ -488,7 +475,7 @@ def pop(self, key, *args):
def setdefault(self, key, default=None):
return self.data.setdefault(ref(key, self._remove),default)
- def update(self, dict=None, **kwargs):
+ def update(self, dict=None, /, **kwargs):
d = self.data
if dict is not None:
if not hasattr(dict, "items"):
1
0
https://github.com/python/cpython/commit/4a686504eb2bbf69adf78077458508a7ba…
commit: 4a686504eb2bbf69adf78077458508a7ba131667
branch: master
author: Yash Aggarwal <Aggarwal.yash2011(a)gmail.com>
committer: Raymond Hettinger <rhettinger(a)users.noreply.github.com>
date: 2019-06-01T00:21:27-07:00
summary:
bpo-35431: Implemented math.comb (GH-11414)
files:
A Misc/NEWS.d/next/Library/2019-01-02-19-48-23.bpo-35431.FhG6QA.rst
M Doc/library/math.rst
M Lib/test/test_math.py
M Modules/clinic/mathmodule.c.h
M Modules/mathmodule.c
diff --git a/Doc/library/math.rst b/Doc/library/math.rst
index b51e96bc4074..5243970df806 100644
--- a/Doc/library/math.rst
+++ b/Doc/library/math.rst
@@ -232,6 +232,21 @@ Number-theoretic and representation functions
:meth:`x.__trunc__() <object.__trunc__>`.
+.. function:: comb(n, k)
+
+ Return the number of ways to choose *k* items from *n* items without repetition
+ and without order.
+
+ Also called the binomial coefficient. It is mathematically equal to the expression
+ ``n! / (k! (n - k)!)``. It is equivalent to the coefficient of k-th term in
+ polynomial expansion of the expression ``(1 + x) ** n``.
+
+ Raises :exc:`TypeError` if the arguments not integers.
+ Raises :exc:`ValueError` if the arguments are negative or if k > n.
+
+ .. versionadded:: 3.8
+
+
Note that :func:`frexp` and :func:`modf` have a different call/return pattern
than their C equivalents: they take a single argument and return a pair of
values, rather than returning their second return value through an 'output
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index 853a0e62f823..9da7f7c4e6e2 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -1862,6 +1862,57 @@ def test_fractions(self):
self.assertAllClose(fraction_examples, rel_tol=1e-8)
self.assertAllNotClose(fraction_examples, rel_tol=1e-9)
+ def testComb(self):
+ comb = math.comb
+ factorial = math.factorial
+ # Test if factorial defintion is satisfied
+ for n in range(100):
+ for k in range(n + 1):
+ self.assertEqual(comb(n, k), factorial(n)
+ // (factorial(k) * factorial(n - k)))
+
+ # Test for Pascal's identity
+ for n in range(1, 100):
+ for k in range(1, n):
+ self.assertEqual(comb(n, k), comb(n - 1, k - 1) + comb(n - 1, k))
+
+ # Test corner cases
+ for n in range(100):
+ self.assertEqual(comb(n, 0), 1)
+ self.assertEqual(comb(n, n), 1)
+
+ for n in range(1, 100):
+ self.assertEqual(comb(n, 1), n)
+ self.assertEqual(comb(n, n - 1), n)
+
+ # Test Symmetry
+ for n in range(100):
+ for k in range(n // 2):
+ self.assertEqual(comb(n, k), comb(n, n - k))
+
+ # Raises TypeError if any argument is non-integer or argument count is
+ # not 2
+ self.assertRaises(TypeError, comb, 10, 1.0)
+ self.assertRaises(TypeError, comb, 10, "1")
+ self.assertRaises(TypeError, comb, "10", 1)
+ self.assertRaises(TypeError, comb, 10.0, 1)
+
+ self.assertRaises(TypeError, comb, 10)
+ self.assertRaises(TypeError, comb, 10, 1, 3)
+ self.assertRaises(TypeError, comb)
+
+ # Raises Value error if not k or n are negative numbers
+ self.assertRaises(ValueError, comb, -1, 1)
+ self.assertRaises(ValueError, comb, -10*10, 1)
+ self.assertRaises(ValueError, comb, 1, -1)
+ self.assertRaises(ValueError, comb, 1, -10*10)
+
+ # Raises value error if k is greater than n
+ self.assertRaises(ValueError, comb, 1, 10**10)
+ self.assertRaises(ValueError, comb, 0, 1)
+
+
+
def test_main():
from doctest import DocFileSuite
diff --git a/Misc/NEWS.d/next/Library/2019-01-02-19-48-23.bpo-35431.FhG6QA.rst b/Misc/NEWS.d/next/Library/2019-01-02-19-48-23.bpo-35431.FhG6QA.rst
new file mode 100644
index 000000000000..34687bdb8a25
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-01-02-19-48-23.bpo-35431.FhG6QA.rst
@@ -0,0 +1,4 @@
+Implement :func:`math.comb` that returns binomial coefficient, that computes
+the number of ways to choose k items from n items without repetition and
+without order.
+Patch by Yash Aggarwal and Keller Fuchs.
diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h
index e677bd896cd8..cba791e2098f 100644
--- a/Modules/clinic/mathmodule.c.h
+++ b/Modules/clinic/mathmodule.c.h
@@ -637,4 +637,53 @@ math_prod(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *k
exit:
return return_value;
}
-/*[clinic end generated code: output=aeed62f403b90199 input=a9049054013a1b77]*/
+
+PyDoc_STRVAR(math_comb__doc__,
+"comb($module, /, n, k)\n"
+"--\n"
+"\n"
+"Number of ways to choose *k* items from *n* items without repetition and without order.\n"
+"\n"
+"Also called the binomial coefficient. It is mathematically equal to the expression\n"
+"n! / (k! * (n - k)!). It is equivalent to the coefficient of k-th term in\n"
+"polynomial expansion of the expression (1 + x)**n.\n"
+"\n"
+"Raises TypeError if the arguments are not integers.\n"
+"Raises ValueError if the arguments are negative or if k > n.");
+
+#define MATH_COMB_METHODDEF \
+ {"comb", (PyCFunction)(void(*)(void))math_comb, METH_FASTCALL|METH_KEYWORDS, math_comb__doc__},
+
+static PyObject *
+math_comb_impl(PyObject *module, PyObject *n, PyObject *k);
+
+static PyObject *
+math_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = {"n", "k", NULL};
+ static _PyArg_Parser _parser = {NULL, _keywords, "comb", 0};
+ PyObject *argsbuf[2];
+ PyObject *n;
+ PyObject *k;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (!PyLong_Check(args[0])) {
+ _PyArg_BadArgument("comb", 1, "int", args[0]);
+ goto exit;
+ }
+ n = args[0];
+ if (!PyLong_Check(args[1])) {
+ _PyArg_BadArgument("comb", 2, "int", args[1]);
+ goto exit;
+ }
+ k = args[1];
+ return_value = math_comb_impl(module, n, k);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=00aa76356759617a input=a9049054013a1b77]*/
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index a153e984ca59..007a8801429c 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -2998,6 +2998,126 @@ math_prod_impl(PyObject *module, PyObject *iterable, PyObject *start)
}
+/*[clinic input]
+math.comb
+
+ n: object(subclass_of='&PyLong_Type')
+ k: object(subclass_of='&PyLong_Type')
+
+Number of ways to choose *k* items from *n* items without repetition and without order.
+
+Also called the binomial coefficient. It is mathematically equal to the expression
+n! / (k! * (n - k)!). It is equivalent to the coefficient of k-th term in
+polynomial expansion of the expression (1 + x)**n.
+
+Raises TypeError if the arguments are not integers.
+Raises ValueError if the arguments are negative or if k > n.
+
+[clinic start generated code]*/
+
+static PyObject *
+math_comb_impl(PyObject *module, PyObject *n, PyObject *k)
+/*[clinic end generated code: output=bd2cec8d854f3493 input=565f340f98efb5b5]*/
+{
+ PyObject *val = NULL,
+ *temp_obj1 = NULL,
+ *temp_obj2 = NULL,
+ *dump_var = NULL;
+ int overflow, cmp;
+ long long i, terms;
+
+ cmp = PyObject_RichCompareBool(n, k, Py_LT);
+ if (cmp < 0) {
+ goto fail_comb;
+ }
+ else if (cmp > 0) {
+ PyErr_Format(PyExc_ValueError,
+ "n must be an integer greater than or equal to k");
+ goto fail_comb;
+ }
+
+ /* b = min(b, a - b) */
+ dump_var = PyNumber_Subtract(n, k);
+ if (dump_var == NULL) {
+ goto fail_comb;
+ }
+ cmp = PyObject_RichCompareBool(k, dump_var, Py_GT);
+ if (cmp < 0) {
+ goto fail_comb;
+ }
+ else if (cmp > 0) {
+ k = dump_var;
+ dump_var = NULL;
+ }
+ else {
+ Py_DECREF(dump_var);
+ dump_var = NULL;
+ }
+
+ terms = PyLong_AsLongLongAndOverflow(k, &overflow);
+ if (terms < 0 && PyErr_Occurred()) {
+ goto fail_comb;
+ }
+ else if (overflow > 0) {
+ PyErr_Format(PyExc_OverflowError,
+ "minimum(n - k, k) must not exceed %lld",
+ LLONG_MAX);
+ goto fail_comb;
+ }
+ else if (overflow < 0 || terms < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "k must be a positive integer");
+ goto fail_comb;
+ }
+
+ if (terms == 0) {
+ return PyNumber_Long(_PyLong_One);
+ }
+
+ val = PyNumber_Long(n);
+ for (i = 1; i < terms; ++i) {
+ temp_obj1 = PyLong_FromSsize_t(i);
+ if (temp_obj1 == NULL) {
+ goto fail_comb;
+ }
+ temp_obj2 = PyNumber_Subtract(n, temp_obj1);
+ if (temp_obj2 == NULL) {
+ goto fail_comb;
+ }
+ dump_var = val;
+ val = PyNumber_Multiply(val, temp_obj2);
+ if (val == NULL) {
+ goto fail_comb;
+ }
+ Py_DECREF(dump_var);
+ dump_var = NULL;
+ Py_DECREF(temp_obj2);
+ temp_obj2 = PyLong_FromUnsignedLongLong((unsigned long long)(i + 1));
+ if (temp_obj2 == NULL) {
+ goto fail_comb;
+ }
+ dump_var = val;
+ val = PyNumber_FloorDivide(val, temp_obj2);
+ if (val == NULL) {
+ goto fail_comb;
+ }
+ Py_DECREF(dump_var);
+ Py_DECREF(temp_obj1);
+ Py_DECREF(temp_obj2);
+ }
+
+ return val;
+
+fail_comb:
+ Py_XDECREF(val);
+ Py_XDECREF(dump_var);
+ Py_XDECREF(temp_obj1);
+ Py_XDECREF(temp_obj2);
+
+ return NULL;
+}
+
+
static PyMethodDef math_methods[] = {
{"acos", math_acos, METH_O, math_acos_doc},
{"acosh", math_acosh, METH_O, math_acosh_doc},
@@ -3047,6 +3167,7 @@ static PyMethodDef math_methods[] = {
{"tanh", math_tanh, METH_O, math_tanh_doc},
MATH_TRUNC_METHODDEF
MATH_PROD_METHODDEF
+ MATH_COMB_METHODDEF
{NULL, NULL} /* sentinel */
};
1
0
bpo-18911: clarify that the minidom XML writer receives texts but not bytes (GH-13718)
by Stefan Behnel 01 Jun '19
by Stefan Behnel 01 Jun '19
01 Jun '19
https://github.com/python/cpython/commit/18e23f227be59241cbb1eeb6d6669771dd…
commit: 18e23f227be59241cbb1eeb6d6669771dd7275fb
branch: 3.7
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: Stefan Behnel <stefan_ml(a)behnel.de>
date: 2019-06-01T08:58:54+02:00
summary:
bpo-18911: clarify that the minidom XML writer receives texts but not bytes (GH-13718)
(cherry picked from commit 5ac0b988fd5f1428efe35329c531c7b5c74d37f6)
Co-authored-by: Windson yang <wiwindson(a)outlook.com>
files:
M Doc/library/xml.dom.minidom.rst
diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst
index 96080c3e318c..c68b0371af70 100644
--- a/Doc/library/xml.dom.minidom.rst
+++ b/Doc/library/xml.dom.minidom.rst
@@ -134,11 +134,12 @@ module documentation. This section lists the differences between the API and
.. method:: Node.writexml(writer, indent="", addindent="", newl="")
- Write XML to the writer object. The writer should have a :meth:`write` method
- which matches that of the file object interface. The *indent* parameter is the
- indentation of the current node. The *addindent* parameter is the incremental
- indentation to use for subnodes of the current one. The *newl* parameter
- specifies the string to use to terminate newlines.
+ Write XML to the writer object. The writer receives texts but not bytes as input,
+ it should have a :meth:`write` method which matches that of the file object
+ interface. The *indent* parameter is the indentation of the current node.
+ The *addindent* parameter is the incremental indentation to use for subnodes
+ of the current one. The *newl* parameter specifies the string to use to
+ terminate newlines.
For the :class:`Document` node, an additional keyword argument *encoding* can
be used to specify the encoding field of the XML header.
1
0
bpo-18911: clarify that the minidom XML writer receives texts but not bytes (GH-13352)
by Stefan Behnel 01 Jun '19
by Stefan Behnel 01 Jun '19
01 Jun '19
https://github.com/python/cpython/commit/5ac0b988fd5f1428efe35329c531c7b5c7…
commit: 5ac0b988fd5f1428efe35329c531c7b5c74d37f6
branch: master
author: Windson yang <wiwindson(a)outlook.com>
committer: Stefan Behnel <stefan_ml(a)behnel.de>
date: 2019-06-01T08:33:16+02:00
summary:
bpo-18911: clarify that the minidom XML writer receives texts but not bytes (GH-13352)
files:
M Doc/library/xml.dom.minidom.rst
diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst
index 2423a0c15691..8711242d95d7 100644
--- a/Doc/library/xml.dom.minidom.rst
+++ b/Doc/library/xml.dom.minidom.rst
@@ -134,11 +134,12 @@ module documentation. This section lists the differences between the API and
.. method:: Node.writexml(writer, indent="", addindent="", newl="")
- Write XML to the writer object. The writer should have a :meth:`write` method
- which matches that of the file object interface. The *indent* parameter is the
- indentation of the current node. The *addindent* parameter is the incremental
- indentation to use for subnodes of the current one. The *newl* parameter
- specifies the string to use to terminate newlines.
+ Write XML to the writer object. The writer receives texts but not bytes as input,
+ it should have a :meth:`write` method which matches that of the file object
+ interface. The *indent* parameter is the indentation of the current node.
+ The *addindent* parameter is the incremental indentation to use for subnodes
+ of the current one. The *newl* parameter specifies the string to use to
+ terminate newlines.
For the :class:`Document` node, an additional keyword argument *encoding* can
be used to specify the encoding field of the XML header.
1
0
https://github.com/python/cpython/commit/354227a1e90036d8c1481a211746de912c…
commit: 354227a1e90036d8c1481a211746de912c6c7c33
branch: master
author: Mario Corchero <mariocj89(a)gmail.com>
committer: Nick Coghlan <ncoghlan(a)gmail.com>
date: 2019-06-01T14:49:09+10:00
summary:
Add option to trace to run modules (GH-5134)
Adds a new option in trace that allows tracing runnable modules. It is
exposed as `--module module_name` as `-m` is already in use for another
argument.
files:
A Misc/NEWS.d/next/Library/2018-01-07-21-04-50.bpo-32515.D8_Wcb.rst
M Doc/library/trace.rst
M Lib/test/test_trace.py
M Lib/trace.py
diff --git a/Doc/library/trace.rst b/Doc/library/trace.rst
index 5cb7029adf5e..85fec6830006 100644
--- a/Doc/library/trace.rst
+++ b/Doc/library/trace.rst
@@ -42,6 +42,9 @@ all Python modules imported during the execution into the current directory.
Display the version of the module and exit.
+.. versionadded:: 3.8
+ Added ``--module`` option that allows to run an executable module.
+
Main options
^^^^^^^^^^^^
diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py
index afe790267661..4bc21eae02ce 100644
--- a/Lib/test/test_trace.py
+++ b/Lib/test/test_trace.py
@@ -474,7 +474,7 @@ class TestCommandLine(unittest.TestCase):
def test_failures(self):
_errors = (
- (b'filename is missing: required with the main options', '-l', '-T'),
+ (b'progname is missing: required with the main options', '-l', '-T'),
(b'cannot specify both --listfuncs and (--trace or --count)', '-lc'),
(b'argument -R/--no-report: not allowed with argument -r/--report', '-rR'),
(b'must specify one of --trace, --count, --report, --listfuncs, or --trackcalls', '-g'),
@@ -524,5 +524,10 @@ def f():
self.assertIn('lines cov% module (path)', stdout)
self.assertIn(f'6 100% {TESTFN} ({filename})', stdout)
+ def test_run_as_module(self):
+ assert_python_ok('-m', 'trace', '-l', '--module', 'timeit', '-n', '1')
+ assert_python_failure('-m', 'trace', '-l', '--module', 'not_a_module_zzz')
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/trace.py b/Lib/trace.py
index 63008a134a8a..62325d3f238a 100755
--- a/Lib/trace.py
+++ b/Lib/trace.py
@@ -666,7 +666,9 @@ def main():
help='Ignore files in the given directory '
'(multiple directories can be joined by os.pathsep).')
- parser.add_argument('filename', nargs='?',
+ parser.add_argument('--module', action='store_true', default=False,
+ help='Trace a module. ')
+ parser.add_argument('progname', nargs='?',
help='file to run as main program')
parser.add_argument('arguments', nargs=argparse.REMAINDER,
help='arguments to the program')
@@ -704,26 +706,40 @@ def parse_ignore_dir(s):
if opts.summary and not opts.count:
parser.error('--summary can only be used with --count or --report')
- if opts.filename is None:
- parser.error('filename is missing: required with the main options')
-
- sys.argv = [opts.filename, *opts.arguments]
- sys.path[0] = os.path.dirname(opts.filename)
+ if opts.progname is None:
+ parser.error('progname is missing: required with the main options')
t = Trace(opts.count, opts.trace, countfuncs=opts.listfuncs,
countcallers=opts.trackcalls, ignoremods=opts.ignore_module,
ignoredirs=opts.ignore_dir, infile=opts.file,
outfile=opts.file, timing=opts.timing)
try:
- with open(opts.filename) as fp:
- code = compile(fp.read(), opts.filename, 'exec')
- # try to emulate __main__ namespace as much as possible
- globs = {
- '__file__': opts.filename,
- '__name__': '__main__',
- '__package__': None,
- '__cached__': None,
- }
+ if opts.module:
+ import runpy
+ module_name = opts.progname
+ mod_name, mod_spec, code = runpy._get_module_details(module_name)
+ sys.argv = [code.co_filename, *opts.arguments]
+ globs = {
+ '__name__': '__main__',
+ '__file__': code.co_filename,
+ '__package__': mod_spec.parent,
+ '__loader__': mod_spec.loader,
+ '__spec__': mod_spec,
+ '__cached__': None,
+ }
+ else:
+ sys.argv = [opts.progname, *opts.arguments]
+ sys.path[0] = os.path.dirname(opts.progname)
+
+ with open(opts.progname) as fp:
+ code = compile(fp.read(), opts.progname, 'exec')
+ # try to emulate __main__ namespace as much as possible
+ globs = {
+ '__file__': opts.progname,
+ '__name__': '__main__',
+ '__package__': None,
+ '__cached__': None,
+ }
t.runctx(code, globs, globs)
except OSError as err:
sys.exit("Cannot run file %r because: %s" % (sys.argv[0], err))
diff --git a/Misc/NEWS.d/next/Library/2018-01-07-21-04-50.bpo-32515.D8_Wcb.rst b/Misc/NEWS.d/next/Library/2018-01-07-21-04-50.bpo-32515.D8_Wcb.rst
new file mode 100644
index 000000000000..ad585b3ab5ed
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-01-07-21-04-50.bpo-32515.D8_Wcb.rst
@@ -0,0 +1 @@
+trace.py can now run modules via python3 -m trace -t --module module_name
1
0