Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1135d85

Browse files
committed
Merge remote-tracking branch 'upstream/main' into asyncio-queue-shutdown
2 parents 6d9edd6 + eefff68 commit 1135d85

23 files changed

Lines changed: 421 additions & 119 deletions

Doc/library/doctest.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ And so on, eventually ending with:
123123
OverflowError: n too large
124124
ok
125125
2 items passed all tests:
126-
1 tests in __main__
127-
8 tests in __main__.factorial
128-
9 tests in 2 items.
129-
9 passed and 0 failed.
126+
1 test in __main__
127+
6 tests in __main__.factorial
128+
7 tests in 2 items.
129+
7 passed.
130130
Test passed.
131131
$
132132
@@ -1933,7 +1933,7 @@ such a test runner::
19331933
optionflags=flags)
19341934
else:
19351935
fail, total = doctest.testmod(optionflags=flags)
1936-
print("{} failures out of {} tests".format(fail, total))
1936+
print(f"{fail} failures out of {total} tests")
19371937

19381938

19391939
.. rubric:: Footnotes

Doc/library/platform.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,39 @@ Linux Platforms
301301
return ids
302302

303303
.. versionadded:: 3.10
304+
305+
306+
Android Platform
307+
----------------
308+
309+
.. function:: android_ver(release="", api_level=0, manufacturer="", \
310+
model="", device="", is_emulator=False)
311+
312+
Get Android device information. Returns a :func:`~collections.namedtuple`
313+
with the following attributes. Values which cannot be determined are set to
314+
the defaults given as parameters.
315+
316+
* ``release`` - Android version, as a string (e.g. ``"14"``).
317+
318+
* ``api_level`` - API level of the running device, as an integer (e.g. ``34``
319+
for Android 14). To get the API level which Python was built against, see
320+
:func:`sys.getandroidapilevel`.
321+
322+
* ``manufacturer`` - `Manufacturer name
323+
<https://developer.android.com/reference/android/os/Build#MANUFACTURER>`__.
324+
325+
* ``model`` - `Model name
326+
<https://developer.android.com/reference/android/os/Build#MODEL>`__ –
327+
typically the marketing name or model number.
328+
329+
* ``device`` - `Device name
330+
<https://developer.android.com/reference/android/os/Build#DEVICE>`__ –
331+
typically the model number or a codename.
332+
333+
* ``is_emulator`` - ``True`` if the device is an emulator; ``False`` if it's
334+
a physical device.
335+
336+
Google maintains a `list of known model and device names
337+
<https://storage.googleapis.com/play_public/supported_devices.html>`__.
338+
339+
.. versionadded:: 3.13

Doc/library/statistics.rst

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,64 @@ The final prediction goes to the largest posterior. This is known as the
11481148
'female'
11491149

11501150

1151+
Sampling from kernel density estimation
1152+
***************************************
1153+
1154+
The :func:`kde()` function creates a continuous probability density
1155+
function from discrete samples. Some applications need a way to make
1156+
random selections from that distribution.
1157+
1158+
The technique is to pick a sample from a bandwidth scaled kernel
1159+
function and recenter the result around a randomly chosen point from
1160+
the input data. This can be done with any kernel that has a known or
1161+
accurately approximated inverse cumulative distribution function.
1162+
1163+
.. testcode::
1164+
1165+
from random import choice, random, seed
1166+
from math import sqrt, log, pi, tan, asin
1167+
from statistics import NormalDist
1168+
1169+
kernel_invcdfs = {
1170+
'normal': NormalDist().inv_cdf,
1171+
'logistic': lambda p: log(p / (1 - p)),
1172+
'sigmoid': lambda p: log(tan(p * pi/2)),
1173+
'rectangular': lambda p: 2*p - 1,
1174+
'triangular': lambda p: sqrt(2*p) - 1 if p < 0.5 else 1 - sqrt(2 - 2*p),
1175+
'cosine': lambda p: 2*asin(2*p - 1)/pi,
1176+
}
1177+
1178+
def kde_random(data, h, kernel='normal'):
1179+
'Return a function that samples from kde() smoothed data.'
1180+
kernel_invcdf = kernel_invcdfs[kernel]
1181+
def rand():
1182+
return h * kernel_invcdf(random()) + choice(data)
1183+
return rand
1184+
1185+
For example:
1186+
1187+
.. doctest::
1188+
1189+
>>> discrete_samples = [-2.1, -1.3, -0.4, 1.9, 5.1, 6.2]
1190+
>>> rand = kde_random(discrete_samples, h=1.5)
1191+
>>> seed(8675309)
1192+
>>> selections = [rand() for i in range(10)]
1193+
>>> [round(x, 1) for x in selections]
1194+
[4.7, 7.4, 1.2, 7.8, 6.9, -1.3, 5.8, 0.2, -1.4, 5.7]
1195+
1196+
.. testcode::
1197+
:hide:
1198+
1199+
from statistics import kde
1200+
from math import isclose
1201+
1202+
# Verify that cdf / invcdf will round trip
1203+
xarr = [i/100 for i in range(-100, 101)]
1204+
for kernel, invcdf in kernel_invcdfs.items():
1205+
cdf = kde([0.0], h=1.0, kernel=kernel, cumulative=True)
1206+
for x in xarr:
1207+
assert isclose(invcdf(cdf(x)), x, abs_tol=1E-9)
1208+
11511209
..
11521210
# This modelines must appear within the last ten lines of the file.
11531211
kate: indent-width 3; remove-trailing-space on; replace-tabs on; encoding utf-8;

Doc/library/sys.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,9 @@ always available.
753753

754754
.. function:: getandroidapilevel()
755755

756-
Return the build time API version of Android as an integer.
756+
Return the build-time API level of Android as an integer. This represents the
757+
minimum version of Android this build of Python can run on. For runtime
758+
version information, see :func:`platform.android_ver`.
757759

758760
.. availability:: Android.
759761

Include/internal/pycore_compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ int _PyCompile_InstructionSequence_UseLabel(_PyCompile_InstructionSequence *seq,
6666
int _PyCompile_InstructionSequence_Addop(_PyCompile_InstructionSequence *seq,
6767
int opcode, int oparg,
6868
_PyCompilerSrcLocation loc);
69+
int _PyCompile_InstructionSequence_ApplyLabelMap(_PyCompile_InstructionSequence *seq);
6970

7071
typedef struct {
7172
PyObject *u_name;

Lib/doctest.py

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,9 +1191,9 @@ class DocTestRunner:
11911191
2 tests in _TestClass
11921192
2 tests in _TestClass.__init__
11931193
2 tests in _TestClass.get
1194-
1 tests in _TestClass.square
1194+
1 test in _TestClass.square
11951195
7 tests in 4 items.
1196-
7 passed and 0 failed.
1196+
7 passed.
11971197
Test passed.
11981198
TestResults(failed=0, attempted=7)
11991199
@@ -1568,49 +1568,59 @@ def summarize(self, verbose=None):
15681568
"""
15691569
if verbose is None:
15701570
verbose = self._verbose
1571-
notests = []
1572-
passed = []
1573-
failed = []
1571+
1572+
notests, passed, failed = [], [], []
15741573
total_tries = total_failures = total_skips = 0
1575-
for item in self._stats.items():
1576-
name, (failures, tries, skips) = item
1574+
1575+
for name, (failures, tries, skips) in self._stats.items():
15771576
assert failures <= tries
15781577
total_tries += tries
15791578
total_failures += failures
15801579
total_skips += skips
1580+
15811581
if tries == 0:
15821582
notests.append(name)
15831583
elif failures == 0:
15841584
passed.append((name, tries))
15851585
else:
1586-
failed.append(item)
1586+
failed.append((name, (failures, tries, skips)))
1587+
15871588
if verbose:
15881589
if notests:
1589-
print(f"{len(notests)} items had no tests:")
1590+
print(f"{_n_items(notests)} had no tests:")
15901591
notests.sort()
15911592
for name in notests:
15921593
print(f" {name}")
1594+
15931595
if passed:
1594-
print(f"{len(passed)} items passed all tests:")
1595-
passed.sort()
1596-
for name, count in passed:
1597-
print(f" {count:3d} tests in {name}")
1596+
print(f"{_n_items(passed)} passed all tests:")
1597+
for name, count in sorted(passed):
1598+
s = "" if count == 1 else "s"
1599+
print(f" {count:3d} test{s} in {name}")
1600+
15981601
if failed:
15991602
print(self.DIVIDER)
1600-
print(f"{len(failed)} items had failures:")
1601-
failed.sort()
1602-
for name, (failures, tries, skips) in failed:
1603+
print(f"{_n_items(failed)} had failures:")
1604+
for name, (failures, tries, skips) in sorted(failed):
16031605
print(f" {failures:3d} of {tries:3d} in {name}")
1606+
16041607
if verbose:
1605-
print(f"{total_tries} tests in {len(self._stats)} items.")
1606-
print(f"{total_tries - total_failures} passed and {total_failures} failed.")
1608+
s = "" if total_tries == 1 else "s"
1609+
print(f"{total_tries} test{s} in {_n_items(self._stats)}.")
1610+
1611+
and_f = f" and {total_failures} failed" if total_failures else ""
1612+
print(f"{total_tries - total_failures} passed{and_f}.")
1613+
16071614
if total_failures:
1608-
msg = f"***Test Failed*** {total_failures} failures"
1615+
s = "" if total_failures == 1 else "s"
1616+
msg = f"***Test Failed*** {total_failures} failure{s}"
16091617
if total_skips:
1610-
msg = f"{msg} and {total_skips} skipped tests"
1618+
s = "" if total_skips == 1 else "s"
1619+
msg = f"{msg} and {total_skips} skipped test{s}"
16111620
print(f"{msg}.")
16121621
elif verbose:
16131622
print("Test passed.")
1623+
16141624
return TestResults(total_failures, total_tries, skipped=total_skips)
16151625

16161626
#/////////////////////////////////////////////////////////////////
@@ -1627,6 +1637,15 @@ def merge(self, other):
16271637
d[name] = (failures, tries, skips)
16281638

16291639

1640+
def _n_items(items: list) -> str:
1641+
"""
1642+
Helper to pluralise the number of items in a list.
1643+
"""
1644+
n = len(items)
1645+
s = "" if n == 1 else "s"
1646+
return f"{n} item{s}"
1647+
1648+
16301649
class OutputChecker:
16311650
"""
16321651
A class used to check the whether the actual output from a doctest

Lib/platform.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,47 @@ def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
542542

543543
return release, vendor, vminfo, osinfo
544544

545+
546+
AndroidVer = collections.namedtuple(
547+
"AndroidVer", "release api_level manufacturer model device is_emulator")
548+
549+
def android_ver(release="", api_level=0, manufacturer="", model="", device="",
550+
is_emulator=False):
551+
if sys.platform == "android":
552+
try:
553+
from ctypes import CDLL, c_char_p, create_string_buffer
554+
except ImportError:
555+
pass
556+
else:
557+
# An NDK developer confirmed that this is an officially-supported
558+
# API (https://stackoverflow.com/a/28416743). Use `getattr` to avoid
559+
# private name mangling.
560+
system_property_get = getattr(CDLL("libc.so"), "__system_property_get")
561+
system_property_get.argtypes = (c_char_p, c_char_p)
562+
563+
def getprop(name, default):
564+
# https://android.googlesource.com/platform/bionic/+/refs/tags/android-5.0.0_r1/libc/include/sys/system_properties.h#39
565+
PROP_VALUE_MAX = 92
566+
buffer = create_string_buffer(PROP_VALUE_MAX)
567+
length = system_property_get(name.encode("UTF-8"), buffer)
568+
if length == 0:
569+
# This API doesn’t distinguish between an empty property and
570+
# a missing one.
571+
return default
572+
else:
573+
return buffer.value.decode("UTF-8", "backslashreplace")
574+
575+
release = getprop("ro.build.version.release", release)
576+
api_level = int(getprop("ro.build.version.sdk", api_level))
577+
manufacturer = getprop("ro.product.manufacturer", manufacturer)
578+
model = getprop("ro.product.model", model)
579+
device = getprop("ro.product.device", device)
580+
is_emulator = getprop("ro.kernel.qemu", "0") == "1"
581+
582+
return AndroidVer(
583+
release, api_level, manufacturer, model, device, is_emulator)
584+
585+
545586
### System name aliasing
546587

547588
def system_alias(system, release, version):
@@ -972,6 +1013,11 @@ def uname():
9721013
system = 'Windows'
9731014
release = 'Vista'
9741015

1016+
# On Android, return the name and version of the OS rather than the kernel.
1017+
if sys.platform == 'android':
1018+
system = 'Android'
1019+
release = android_ver().release
1020+
9751021
vals = system, node, release, version, machine
9761022
# Replace 'unknown' values with the more portable ''
9771023
_uname_cache = uname_result(*map(_unknown_as_blank, vals))

Lib/test/pythoninfo.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ def collect_platform(info_add):
179179
info_add(f'platform.freedesktop_os_release[{key}]',
180180
os_release[key])
181181

182+
if sys.platform == 'android':
183+
call_func(info_add, 'platform.android_ver', platform, 'android_ver')
184+
182185

183186
def collect_locale(info_add):
184187
import locale

Lib/test/support/__init__.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,18 +1801,18 @@ def missing_compiler_executable(cmd_names=[]):
18011801
return cmd[0]
18021802

18031803

1804-
_is_android_emulator = None
1804+
_old_android_emulator = None
18051805
def setswitchinterval(interval):
18061806
# Setting a very low gil interval on the Android emulator causes python
18071807
# to hang (issue #26939).
1808-
minimum_interval = 1e-5
1808+
minimum_interval = 1e-4 # 100 us
18091809
if is_android and interval < minimum_interval:
1810-
global _is_android_emulator
1811-
if _is_android_emulator is None:
1812-
import subprocess
1813-
_is_android_emulator = (subprocess.check_output(
1814-
['getprop', 'ro.kernel.qemu']).strip() == b'1')
1815-
if _is_android_emulator:
1810+
global _old_android_emulator
1811+
if _old_android_emulator is None:
1812+
import platform
1813+
av = platform.android_ver()
1814+
_old_android_emulator = av.is_emulator and av.api_level < 24
1815+
if _old_android_emulator:
18161816
interval = minimum_interval
18171817
return sys.setswitchinterval(interval)
18181818

Lib/test/test_asyncio/test_base_events.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import concurrent.futures
44
import errno
55
import math
6+
import platform
67
import socket
78
import sys
89
import threading
@@ -1430,6 +1431,10 @@ def test_create_connection_no_inet_pton(self, m_socket):
14301431
self._test_create_connection_ip_addr(m_socket, False)
14311432

14321433
@patch_socket
1434+
@unittest.skipIf(
1435+
support.is_android and platform.android_ver().api_level < 23,
1436+
"Issue gh-71123: this fails on Android before API level 23"
1437+
)
14331438
def test_create_connection_service_name(self, m_socket):
14341439
m_socket.getaddrinfo = socket.getaddrinfo
14351440
sock = m_socket.socket.return_value

0 commit comments

Comments
 (0)