Skip to content

Commit

Permalink
Merge branch 'main' into deepcopy_skip_memo
Browse files Browse the repository at this point in the history
  • Loading branch information
eendebakpt authored Sep 26, 2023
2 parents 2260fca + ecd813f commit 0816d78
Show file tree
Hide file tree
Showing 38 changed files with 434 additions and 159 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ jobs:
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
run: .\PCbuild\rt.bat -p Win32 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
run: .\PCbuild\rt.bat -p Win32 -d -q --fast-ci

build_win_amd64:
name: 'Windows (x64)'
Expand All @@ -201,7 +201,7 @@ jobs:
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
run: .\PCbuild\rt.bat -p x64 -d -q --fast-ci

build_win_arm64:
name: 'Windows (arm64)'
Expand Down Expand Up @@ -252,7 +252,7 @@ jobs:
- name: Display build info
run: make pythoninfo
- name: Tests
run: make buildbottest TESTOPTS="-j4 -uall,-cpu"
run: make test

build_ubuntu:
name: 'Ubuntu'
Expand Down Expand Up @@ -319,7 +319,7 @@ jobs:
run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw
- name: Tests
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
run: xvfb-run make test

build_ubuntu_ssltests:
name: 'Ubuntu SSL tests with OpenSSL'
Expand Down Expand Up @@ -535,7 +535,7 @@ jobs:
- name: Display build info
run: make pythoninfo
- name: Tests
run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
run: xvfb-run make test

all-required-green: # This job does nothing and is only used for the branch protection
name: All required checks pass
Expand Down
14 changes: 9 additions & 5 deletions Doc/library/pathlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1381,15 +1381,19 @@ call fails (for example because the path doesn't exist).
>>> p.resolve()
PosixPath('/home/antoine/pathlib/setup.py')

If the path doesn't exist and *strict* is ``True``, :exc:`FileNotFoundError`
is raised. If *strict* is ``False``, the path is resolved as far as possible
and any remainder is appended without checking whether it exists. If an
infinite loop is encountered along the resolution path, :exc:`RuntimeError`
is raised.
If a path doesn't exist or a symlink loop is encountered, and *strict* is
``True``, :exc:`OSError` is raised. If *strict* is ``False``, the path is
resolved as far as possible and any remainder is appended without checking
whether it exists.

.. versionchanged:: 3.6
The *strict* parameter was added (pre-3.6 behavior is strict).

.. versionchanged:: 3.13
Symlink loops are treated like other errors: :exc:`OSError` is raised in
strict mode, and no exception is raised in non-strict mode. In previous
versions, :exc:`RuntimeError` is raised no matter the value of *strict*.

.. method:: Path.rglob(pattern, *, case_sensitive=None, follow_symlinks=None)

Glob the given relative *pattern* recursively. This is like calling
Expand Down
19 changes: 9 additions & 10 deletions Doc/library/weakref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ See :ref:`__slots__ documentation <slots>` for details.

Exceptions raised by the callback will be noted on the standard error output,
but cannot be propagated; they are handled in exactly the same way as exceptions
raised from an object's :meth:`__del__` method.
raised from an object's :meth:`~object.__del__` method.

Weak references are :term:`hashable` if the *object* is hashable. They will
maintain their hash value even after the *object* was deleted. If
Expand Down Expand Up @@ -221,8 +221,7 @@ than needed.
Added support for ``|`` and ``|=`` operators, as specified in :pep:`584`.

:class:`WeakValueDictionary` objects have an additional method that has the
same issues as the :meth:`keyrefs` method of :class:`WeakKeyDictionary`
objects.
same issues as the :meth:`WeakKeyDictionary.keyrefs` method.


.. method:: WeakValueDictionary.valuerefs()
Expand Down Expand Up @@ -281,7 +280,7 @@ objects.
Exceptions raised by finalizer callbacks during garbage collection
will be shown on the standard error output, but cannot be
propagated. They are handled in the same way as exceptions raised
from an object's :meth:`__del__` method or a weak reference's
from an object's :meth:`~object.__del__` method or a weak reference's
callback.

When the program exits, each remaining live finalizer is called
Expand Down Expand Up @@ -523,18 +522,18 @@ is still alive. For instance
obj dead or exiting


Comparing finalizers with :meth:`__del__` methods
-------------------------------------------------
Comparing finalizers with :meth:`~object.__del__` methods
---------------------------------------------------------

Suppose we want to create a class whose instances represent temporary
directories. The directories should be deleted with their contents
when the first of the following events occurs:

* the object is garbage collected,
* the object's :meth:`remove` method is called, or
* the object's :meth:`!remove` method is called, or
* the program exits.

We might try to implement the class using a :meth:`__del__` method as
We might try to implement the class using a :meth:`~object.__del__` method as
follows::

class TempDir:
Expand All @@ -553,12 +552,12 @@ follows::
def __del__(self):
self.remove()

Starting with Python 3.4, :meth:`__del__` methods no longer prevent
Starting with Python 3.4, :meth:`~object.__del__` methods no longer prevent
reference cycles from being garbage collected, and module globals are
no longer forced to :const:`None` during :term:`interpreter shutdown`.
So this code should work without any issues on CPython.

However, handling of :meth:`__del__` methods is notoriously implementation
However, handling of :meth:`~object.__del__` methods is notoriously implementation
specific, since it depends on internal details of the interpreter's garbage
collector implementation.

Expand Down
1 change: 0 additions & 1 deletion Doc/tools/.nitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ Doc/library/unittest.mock.rst
Doc/library/unittest.rst
Doc/library/urllib.parse.rst
Doc/library/urllib.request.rst
Doc/library/weakref.rst
Doc/library/wsgiref.rst
Doc/library/xml.dom.minidom.rst
Doc/library/xml.dom.pulldom.rst
Expand Down
15 changes: 12 additions & 3 deletions Doc/using/configure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -964,9 +964,18 @@ Main Makefile targets
You can use the configure :option:`--enable-optimizations` option to make
this the default target of the ``make`` command (``make all`` or just
``make``).
* ``make buildbottest``: Build Python and run the Python test suite, the same
way than buildbots test Python. Set ``TESTTIMEOUT`` variable (in seconds)
to change the test timeout (1200 by default: 20 minutes).

* ``make test``: Build Python and run the Python test suite with ``--slow-ci``
option. Variables:

* ``TESTOPTS``: additional regrtest command line options.
* ``TESTPYTHONOPTS``: additional Python command line options.
* ``TESTTIMEOUT``: timeout in seconds (default: 20 minutes).

* ``make buildbottest``: Similar to ``make test``, but use ``--slow-ci``
option and default timeout of 20 minutes, instead of ``--fast-ci`` option
and a default timeout of 10 minutes.

* ``make install``: Build and install Python.
* ``make regen-all``: Regenerate (almost) all generated files;
``make regen-stdlib-module-names`` and ``autoconf`` must be run separately
Expand Down
2 changes: 1 addition & 1 deletion Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ random
* Add :func:`random.binomialvariate`.
(Contributed by Raymond Hettinger in :gh:`81620`.)

* Add a default of ``lamb=1.0`` to :func:`random.expovariate`.
* Add a default of ``lambd=1.0`` to :func:`random.expovariate`.
(Contributed by Raymond Hettinger in :gh:`100234`.)

shutil
Expand Down
3 changes: 2 additions & 1 deletion Lib/concurrent/futures/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,8 @@ def terminate_broken(self, cause):

# gh-107219: Close the connection writer which can unblock
# Queue._feed() if it was stuck in send_bytes().
self.call_queue._writer.close()
if sys.platform == 'win32':
self.call_queue._writer.close()

# clean up resources
self.join_executor_internals()
Expand Down
3 changes: 1 addition & 2 deletions Lib/multiprocessing/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
BUFSIZE = 8192
# A very generous timeout when it comes to local connections...
CONNECTION_TIMEOUT = 20.
WSA_OPERATION_ABORTED = 995

_mmap_counter = itertools.count()

Expand Down Expand Up @@ -300,7 +299,7 @@ def _send_bytes(self, buf):
finally:
self._send_ov = None
nwritten, err = ov.GetOverlappedResult(True)
if err == WSA_OPERATION_ABORTED:
if err == _winapi.ERROR_OPERATION_ABORTED:
# close() was called by another thread while
# WaitForMultipleObjects() was waiting for the overlapped
# operation.
Expand Down
34 changes: 32 additions & 2 deletions Lib/multiprocessing/resource_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,31 @@
})


class ReentrantCallError(RuntimeError):
pass


class ResourceTracker(object):

def __init__(self):
self._lock = threading.Lock()
self._lock = threading.RLock()
self._fd = None
self._pid = None

def _reentrant_call_error(self):
# gh-109629: this happens if an explicit call to the ResourceTracker
# gets interrupted by a garbage collection, invoking a finalizer (*)
# that itself calls back into ResourceTracker.
# (*) for example the SemLock finalizer
raise ReentrantCallError(
"Reentrant call into the multiprocessing resource tracker")

def _stop(self):
with self._lock:
# This should not happen (_stop() isn't called by a finalizer)
# but we check for it anyway.
if self._lock._recursion_count() > 1:
return self._reentrant_call_error()
if self._fd is None:
# not running
return
Expand All @@ -81,6 +97,9 @@ def ensure_running(self):
This can be run from any process. Usually a child process will use
the resource created by its parent.'''
with self._lock:
if self._lock._recursion_count() > 1:
# The code below is certainly not reentrant-safe, so bail out
return self._reentrant_call_error()
if self._fd is not None:
# resource tracker was launched before, is it still running?
if self._check_alive():
Expand Down Expand Up @@ -159,7 +178,17 @@ def unregister(self, name, rtype):
self._send('UNREGISTER', name, rtype)

def _send(self, cmd, name, rtype):
self.ensure_running()
try:
self.ensure_running()
except ReentrantCallError:
# The code below might or might not work, depending on whether
# the resource tracker was already running and still alive.
# Better warn the user.
# (XXX is warnings.warn itself reentrant-safe? :-)
warnings.warn(
f"ResourceTracker called reentrantly for resource cleanup, "
f"which is unsupported. "
f"The {rtype} object {name!r} might leak.")
msg = '{0}:{1}:{2}\n'.format(cmd, name, rtype).encode('ascii')
if len(msg) > 512:
# posix guarantees that writes to a pipe of less than PIPE_BUF
Expand All @@ -176,6 +205,7 @@ def _send(self, cmd, name, rtype):
unregister = _resource_tracker.unregister
getfd = _resource_tracker.getfd


def main(fd):
'''Run resource tracker.'''
# protect the process from ^C and "killall python" etc
Expand Down
21 changes: 1 addition & 20 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1230,26 +1230,7 @@ def resolve(self, strict=False):
normalizing it.
"""

def check_eloop(e):
winerror = getattr(e, 'winerror', 0)
if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME:
raise RuntimeError("Symlink loop from %r" % e.filename)

try:
s = os.path.realpath(self, strict=strict)
except OSError as e:
check_eloop(e)
raise
p = self.with_segments(s)

# In non-strict mode, realpath() doesn't raise on symlink loops.
# Ensure we get an exception by calling stat()
if not strict:
try:
p.stat()
except OSError as e:
check_eloop(e)
return p
return self.with_segments(os.path.realpath(self, strict=strict))

def owner(self):
"""
Expand Down
39 changes: 34 additions & 5 deletions Lib/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,14 @@ def choices(self, population, weights=None, *, cum_weights=None, k=1):
## -------------------- real-valued distributions -------------------

def uniform(self, a, b):
"Get a random number in the range [a, b) or [a, b] depending on rounding."
"""Get a random number in the range [a, b) or [a, b] depending on rounding.
The mean (expected value) and variance of the random variable are:
E[X] = (a + b) / 2
Var[X] = (b - a) ** 2 / 12
"""
return a + (b - a) * self.random()

def triangular(self, low=0.0, high=1.0, mode=None):
Expand All @@ -503,6 +510,11 @@ def triangular(self, low=0.0, high=1.0, mode=None):
http://en.wikipedia.org/wiki/Triangular_distribution
The mean (expected value) and variance of the random variable are:
E[X] = (low + high + mode) / 3
Var[X] = (low**2 + high**2 + mode**2 - low*high - low*mode - high*mode) / 18
"""
u = self.random()
try:
Expand Down Expand Up @@ -593,12 +605,15 @@ def expovariate(self, lambd=1.0):
positive infinity if lambd is positive, and from negative
infinity to 0 if lambd is negative.
"""
# lambd: rate lambd = 1/mean
# ('lambda' is a Python reserved word)
The mean (expected value) and variance of the random variable are:
E[X] = 1 / lambd
Var[X] = 1 / lambd ** 2
"""
# we use 1-random() instead of random() to preclude the
# possibility of taking the log of zero.

return -_log(1.0 - self.random()) / lambd

def vonmisesvariate(self, mu, kappa):
Expand Down Expand Up @@ -654,8 +669,12 @@ def gammavariate(self, alpha, beta):
pdf(x) = --------------------------------------
math.gamma(alpha) * beta ** alpha
The mean (expected value) and variance of the random variable are:
E[X] = alpha * beta
Var[X] = alpha * beta ** 2
"""
# alpha > 0, beta > 0, mean is alpha*beta, variance is alpha*beta**2

# Warning: a few older sources define the gamma distribution in terms
# of alpha > -1.0
Expand Down Expand Up @@ -714,6 +733,11 @@ def betavariate(self, alpha, beta):
Conditions on the parameters are alpha > 0 and beta > 0.
Returned values range between 0 and 1.
The mean (expected value) and variance of the random variable are:
E[X] = alpha / (alpha + beta)
Var[X] = alpha * beta / ((alpha + beta)**2 * (alpha + beta + 1))
"""
## See
## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html
Expand Down Expand Up @@ -766,6 +790,11 @@ def binomialvariate(self, n=1, p=0.5):
Returns an integer in the range: 0 <= X <= n
The mean (expected value) and variance of the random variable are:
E[X] = n * p
Var[x] = n * p * (1 - p)
"""
# Error check inputs and handle edge cases
if n < 0:
Expand Down
Loading

0 comments on commit 0816d78

Please sign in to comment.