Skip to content

Commit 9836ffa

Browse files
committed
Merge branch 'main' into tachyon-ndjson-kolektor
* main: pythongh-145458: use `self.skip_idle` consistently in the tachyon profiler (python#145459) pythongh-146615: Fix format specifiers in Objects/ directory (pythonGH-146620) pythongh-146615: Fix format specifiers in Python/ directory (pythonGH-146619) pythongh-146615: Fix format specifiers in test cextensions (pythonGH-146618) pythongh-146615: Fix format specifiers in extension modules (pythonGH-146617) pythongh-146615: Fix crash in __get__() for METH_METHOD descriptors with invalid type argument (pythonGH-146634) pythongh-146376: Reduce timeout in Emscripten GHA workflow (python#146378) pythongh-146442: Fix various bugs in compiler pipeline (python#146443) pythongh-146238: Support half-floats in the array module (python#146242) pythongh-145056: Add support for merging collections.UserDict and frozendict (pythonGH-146465) pythongh-145056: Fix merging of collections.OrderedDict and frozendict (pythonGH-146466) pythongh-139633: Run netrc file permission check only once per parse (pythonGH-139634)
2 parents f71252e + b4fac15 commit 9836ffa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+253
-96
lines changed

.github/workflows/reusable-emscripten.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
build-emscripten-reusable:
1111
name: 'build and test'
1212
runs-on: ubuntu-24.04
13-
timeout-minutes: 60
13+
timeout-minutes: 40
1414
steps:
1515
- uses: actions/checkout@v6
1616
with:

Doc/library/array.rst

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ defined:
4242
+-----------+--------------------+-------------------+-----------------------+-------+
4343
| ``'Q'`` | unsigned long long | int | 8 | |
4444
+-----------+--------------------+-------------------+-----------------------+-------+
45+
| ``'e'`` | _Float16 | float | 2 | \(3) |
46+
+-----------+--------------------+-------------------+-----------------------+-------+
4547
| ``'f'`` | float | float | 4 | |
4648
+-----------+--------------------+-------------------+-----------------------+-------+
4749
| ``'d'`` | double | float | 8 | |
4850
+-----------+--------------------+-------------------+-----------------------+-------+
49-
| ``'F'`` | float complex | complex | 8 | \(3) |
51+
| ``'F'`` | float complex | complex | 8 | \(4) |
5052
+-----------+--------------------+-------------------+-----------------------+-------+
51-
| ``'D'`` | double complex | complex | 16 | \(3) |
53+
| ``'D'`` | double complex | complex | 16 | \(4) |
5254
+-----------+--------------------+-------------------+-----------------------+-------+
5355

5456

@@ -69,6 +71,15 @@ Notes:
6971
.. versionadded:: 3.13
7072

7173
(3)
74+
The IEEE 754 binary16 "half precision" type was introduced in the 2008
75+
revision of the `IEEE 754 standard <ieee 754 standard_>`_.
76+
This type is not widely supported by C compilers. It's available
77+
as :c:expr:`_Float16` type, if the compiler supports the Annex H
78+
of the C23 standard.
79+
80+
.. versionadded:: next
81+
82+
(4)
7283
Complex types (``F`` and ``D``) are available unconditionally,
7384
regardless on support for complex types (the Annex G of the C11 standard)
7485
by the C compiler.
@@ -304,3 +315,5 @@ Examples::
304315

305316
`NumPy <https://numpy.org/>`_
306317
The NumPy package defines another array type.
318+
319+
.. _ieee 754 standard: https://en.wikipedia.org/wiki/IEEE_754-2008_revision

Doc/whatsnew/3.15.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ array
642642
formatting characters ``'F'`` and ``'D'`` respectively.
643643
(Contributed by Sergey B Kirpichev in :gh:`146151`.)
644644

645+
* Support half-floats (16-bit IEEE 754 binary interchange format): formatting
646+
character ``'e'``.
647+
(Contributed by Sergey B Kirpichev in :gh:`146238`.)
648+
645649

646650
base64
647651
------

Lib/collections/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,14 @@ def __ior__(self, other):
328328
return self
329329

330330
def __or__(self, other):
331-
if not isinstance(other, dict):
331+
if not isinstance(other, (dict, frozendict)):
332332
return NotImplemented
333333
new = self.__class__(self)
334334
new.update(other)
335335
return new
336336

337337
def __ror__(self, other):
338-
if not isinstance(other, dict):
338+
if not isinstance(other, (dict, frozendict)):
339339
return NotImplemented
340340
new = self.__class__(other)
341341
new.update(self)
@@ -1216,14 +1216,14 @@ def __repr__(self):
12161216
def __or__(self, other):
12171217
if isinstance(other, UserDict):
12181218
return self.__class__(self.data | other.data)
1219-
if isinstance(other, dict):
1219+
if isinstance(other, (dict, frozendict)):
12201220
return self.__class__(self.data | other)
12211221
return NotImplemented
12221222

12231223
def __ror__(self, other):
12241224
if isinstance(other, UserDict):
12251225
return self.__class__(other.data | self.data)
1226-
if isinstance(other, dict):
1226+
if isinstance(other, (dict, frozendict)):
12271227
return self.__class__(other | self.data)
12281228
return NotImplemented
12291229

Lib/netrc.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -152,23 +152,28 @@ def _parse(self, file, fp, default_netrc):
152152
else:
153153
raise NetrcParseError("bad follower token %r" % tt,
154154
file, lexer.lineno)
155-
self._security_check(fp, default_netrc, self.hosts[entryname][0])
156-
157-
def _security_check(self, fp, default_netrc, login):
158-
if _can_security_check() and default_netrc and login != "anonymous":
159-
prop = os.fstat(fp.fileno())
160-
current_user_id = os.getuid()
161-
if prop.st_uid != current_user_id:
162-
fowner = _getpwuid(prop.st_uid)
163-
user = _getpwuid(current_user_id)
164-
raise NetrcParseError(
165-
f"~/.netrc file owner ({fowner}) does not match"
166-
f" current user ({user})")
167-
if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):
168-
raise NetrcParseError(
169-
"~/.netrc access too permissive: access"
170-
" permissions must restrict access to only"
171-
" the owner")
155+
156+
if _can_security_check() and default_netrc:
157+
for entry in self.hosts.values():
158+
if entry[0] != "anonymous":
159+
# Raises on security issue; once passed once can exit.
160+
self._security_check(fp)
161+
return
162+
163+
def _security_check(self, fp):
164+
prop = os.fstat(fp.fileno())
165+
current_user_id = os.getuid()
166+
if prop.st_uid != current_user_id:
167+
fowner = _getpwuid(prop.st_uid)
168+
user = _getpwuid(current_user_id)
169+
raise NetrcParseError(
170+
f"~/.netrc file owner ({fowner}) does not match"
171+
f" current user ({user})")
172+
if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):
173+
raise NetrcParseError(
174+
"~/.netrc access too permissive: access"
175+
" permissions must restrict access to only"
176+
" the owner")
172177

173178
def authenticators(self, host):
174179
"""Return a (user, account, password) tuple for given host."""

Lib/profiling/sampling/stack_collector.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ def __init__(self, sample_interval_usec, *, skip_idle=False):
1919
self.sample_interval_usec = sample_interval_usec
2020
self.skip_idle = skip_idle
2121

22-
def collect(self, stack_frames, timestamps_us=None, skip_idle=False):
22+
def collect(self, stack_frames, timestamps_us=None):
2323
weight = len(timestamps_us) if timestamps_us else 1
24-
for frames, thread_id in self._iter_stacks(stack_frames, skip_idle=skip_idle):
24+
for frames, thread_id in self._iter_stacks(stack_frames, skip_idle=self.skip_idle):
2525
self.process_frames(frames, thread_id, weight=weight)
2626

2727
def process_frames(self, frames, thread_id, weight=1):
@@ -88,7 +88,7 @@ def __init__(self, *args, **kwargs):
8888
# Per-thread statistics
8989
self.per_thread_stats = {} # {thread_id: {has_gil, on_cpu, gil_requested, unknown, has_exception, total, gc_samples}}
9090

91-
def collect(self, stack_frames, timestamps_us=None, skip_idle=False):
91+
def collect(self, stack_frames, timestamps_us=None):
9292
"""Override to track thread status statistics before processing frames."""
9393
# Weight is number of timestamps (samples with identical stack)
9494
weight = len(timestamps_us) if timestamps_us else 1
@@ -123,7 +123,7 @@ def collect(self, stack_frames, timestamps_us=None, skip_idle=False):
123123
self.per_thread_stats[thread_id][key] += value * weight
124124

125125
# Call parent collect to process frames
126-
super().collect(stack_frames, timestamps_us, skip_idle=skip_idle)
126+
super().collect(stack_frames, timestamps_us)
127127

128128
def set_stats(self, sample_interval_usec, duration_sec, sample_rate,
129129
error_rate=None, missed_samples=None, mode=None):

Lib/test/test_array.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class ArraySubclassWithKwargs(array.array):
3131
def __init__(self, typecode, newarg=None):
3232
array.array.__init__(self)
3333

34-
typecodes = 'uwbBhHiIlLfdqQFD'
34+
typecodes = 'uwbBhHiIlLfdqQFDe'
3535

3636
class MiscTest(unittest.TestCase):
3737

@@ -117,8 +117,10 @@ def __index__(self):
117117
IEEE_754_FLOAT_COMPLEX_BE = 23
118118
IEEE_754_DOUBLE_COMPLEX_LE = 24
119119
IEEE_754_DOUBLE_COMPLEX_BE = 25
120+
IEEE_754_FLOAT16_LE = 26
121+
IEEE_754_FLOAT16_BE = 27
120122

121-
MACHINE_FORMAT_CODE_MAX = 25
123+
MACHINE_FORMAT_CODE_MAX = 27
122124

123125

124126
class ArrayReconstructorTest(unittest.TestCase):
@@ -1588,6 +1590,13 @@ def test_byteswap(self):
15881590
self.assertEqual(a, b)
15891591

15901592

1593+
class HalfFloatTest(FPTest, unittest.TestCase):
1594+
example = [-42.0, 0, 42, 1e2, -1e4]
1595+
smallerexample = [-42.0, 0, 42, 1e2, -2e4]
1596+
biggerexample = [-42.0, 0, 42, 1e2, 1e4]
1597+
typecode = 'e'
1598+
minitemsize = 2
1599+
15911600
class FloatTest(FPTest, unittest.TestCase):
15921601
typecode = 'f'
15931602
minitemsize = 4

Lib/test/test_descr.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,6 +1803,28 @@ class SubSpam(spam.spamlist): pass
18031803
spam_cm.__get__(None, list)
18041804
self.assertEqual(str(cm.exception), expected_errmsg)
18051805

1806+
@support.cpython_only
1807+
def test_method_get_meth_method_invalid_type(self):
1808+
# gh-146615: method_get() for METH_METHOD descriptors used to pass
1809+
# Py_TYPE(type)->tp_name as the %V fallback instead of the separate
1810+
# %s argument, causing a missing argument for %s and a crash.
1811+
# Verify the error message is correct when __get__() is called with a
1812+
# non-type as the second argument.
1813+
#
1814+
# METH_METHOD|METH_FASTCALL|METH_KEYWORDS is the only flag combination
1815+
# that enters the affected branch in method_get().
1816+
import io
1817+
1818+
obj = io.StringIO()
1819+
descr = io.TextIOBase.read
1820+
1821+
with self.assertRaises(TypeError) as cm:
1822+
descr.__get__(obj, "not_a_type")
1823+
self.assertEqual(
1824+
str(cm.exception),
1825+
"descriptor 'read' needs a type, not 'str', as arg 2",
1826+
)
1827+
18061828
def test_staticmethods(self):
18071829
# Testing static methods...
18081830
class C(object):

Lib/test/test_netrc.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import netrc, os, unittest, sys, textwrap
2+
from pathlib import Path
23
from test import support
34
from test.support import os_helper
5+
from unittest.mock import patch
6+
47

58
temp_filename = os_helper.TESTFN
69

@@ -309,6 +312,26 @@ def test_security(self):
309312
self.assertEqual(nrc.hosts['foo.domain.com'],
310313
('anonymous', '', 'pass'))
311314

315+
@unittest.skipUnless(os.name == 'posix', 'POSIX only test')
316+
@unittest.skipUnless(hasattr(os, 'getuid'), "os.getuid is required")
317+
@os_helper.skip_unless_working_chmod
318+
def test_security_only_once(self):
319+
# Make sure security check is only run once per parse when multiple
320+
# entries are found.
321+
with patch.object(netrc.netrc, "_security_check") as mock:
322+
with os_helper.temp_dir() as tmp_dir:
323+
netrc_path = Path(tmp_dir) / '.netrc'
324+
netrc_path.write_text("""\
325+
machine foo.domain.com login bar password pass
326+
machine bar.domain.com login foo password pass
327+
""")
328+
netrc_path.chmod(0o600)
329+
with os_helper.EnvironmentVarGuard() as environ:
330+
environ.set('HOME', tmp_dir)
331+
netrc.netrc()
332+
333+
mock.assert_called_once()
334+
312335

313336
if __name__ == "__main__":
314337
unittest.main()

Lib/test/test_ordered_dict.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ def test_merge_operator(self):
698698
d |= list(b.items())
699699
expected = OrderedDict({0: 0, 1: 1, 2: 2, 3: 3})
700700
self.assertEqual(a | dict(b), expected)
701+
self.assertEqual(a | frozendict(b), expected)
701702
self.assertEqual(a | b, expected)
702703
self.assertEqual(c, expected)
703704
self.assertEqual(d, expected)
@@ -706,12 +707,17 @@ def test_merge_operator(self):
706707
c |= a
707708
expected = OrderedDict({1: 1, 2: 1, 3: 3, 0: 0})
708709
self.assertEqual(dict(b) | a, expected)
710+
self.assertEqual(frozendict(b) | a, expected)
711+
self.assertEqual(a.__ror__(frozendict(b)), expected)
709712
self.assertEqual(b | a, expected)
710713
self.assertEqual(c, expected)
711714

712715
self.assertIs(type(a | b), OrderedDict)
713716
self.assertIs(type(dict(a) | b), OrderedDict)
717+
self.assertIs(type(frozendict(a) | b), frozendict)
718+
self.assertIs(type(b.__ror__(frozendict(a))), OrderedDict)
714719
self.assertIs(type(a | dict(b)), OrderedDict)
720+
self.assertIs(type(a | frozendict(b)), OrderedDict)
715721

716722
expected = a.copy()
717723
a |= ()

0 commit comments

Comments
 (0)