Skip to content

Commit 0adf726

Browse files
authored
Merge branch 'main' into compare_op
2 parents 7457d45 + bbfd9c9 commit 0adf726

33 files changed

+283
-138
lines changed

Doc/c-api/allocation.rst

+2-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ Allocating Objects on the Heap
1515
.. c:function:: PyObject* PyObject_Init(PyObject *op, PyTypeObject *type)
1616
1717
Initialize a newly allocated object *op* with its type and initial
18-
reference. Returns the initialized object. If *type* indicates that the
19-
object participates in the cyclic garbage detector, it is added to the
20-
detector's set of observed objects. Other fields of the object are not
21-
affected.
18+
reference. Returns the initialized object. Other fields of the object are
19+
not affected.
2220
2321
2422
.. c:function:: PyVarObject* PyObject_InitVar(PyVarObject *op, PyTypeObject *type, Py_ssize_t size)

Doc/library/configparser.rst

+28-3
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,13 @@ interpolation if an option used is not defined elsewhere. ::
942942
ConfigParser Objects
943943
--------------------
944944

945-
.. class:: ConfigParser(defaults=None, dict_type=dict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=('#', ';'), inline_comment_prefixes=None, strict=True, empty_lines_in_values=True, default_section=configparser.DEFAULTSECT, interpolation=BasicInterpolation(), converters={})
945+
.. class:: ConfigParser(defaults=None, dict_type=dict, allow_no_value=False, *, \
946+
delimiters=('=', ':'), comment_prefixes=('#', ';'), \
947+
inline_comment_prefixes=None, strict=True, \
948+
empty_lines_in_values=True, \
949+
default_section=configparser.DEFAULTSECT, \
950+
interpolation=BasicInterpolation(), converters={}, \
951+
allow_unnamed_section=False)
946952

947953
The main configuration parser. When *defaults* is given, it is initialized
948954
into the dictionary of intrinsic defaults. When *dict_type* is given, it
@@ -990,6 +996,10 @@ ConfigParser Objects
990996
converter gets its own corresponding :meth:`!get*` method on the parser
991997
object and section proxies.
992998

999+
When *allow_unnamed_section* is ``True`` (default: ``False``),
1000+
the first section name can be omitted. See the
1001+
`"Unnamed Sections" section <#unnamed-sections>`_.
1002+
9931003
It is possible to read several configurations into a single
9941004
:class:`ConfigParser`, where the most recently added configuration has the
9951005
highest priority. Any conflicting keys are taken from the more recent
@@ -1039,6 +1049,9 @@ ConfigParser Objects
10391049
Raise a :exc:`MultilineContinuationError` when *allow_no_value* is
10401050
``True``, and a key without a value is continued with an indented line.
10411051

1052+
.. versionchanged:: 3.13
1053+
The *allow_unnamed_section* argument was added.
1054+
10421055
.. method:: defaults()
10431056

10441057
Return a dictionary containing the instance-wide defaults.
@@ -1295,18 +1308,30 @@ RawConfigParser Objects
12951308
comment_prefixes=('#', ';'), \
12961309
inline_comment_prefixes=None, strict=True, \
12971310
empty_lines_in_values=True, \
1298-
default_section=configparser.DEFAULTSECT[, \
1299-
interpolation])
1311+
default_section=configparser.DEFAULTSECT, \
1312+
interpolation=BasicInterpolation(), converters={}, \
1313+
allow_unnamed_section=False)
13001314
13011315
Legacy variant of the :class:`ConfigParser`. It has interpolation
13021316
disabled by default and allows for non-string section names, option
13031317
names, and values via its unsafe ``add_section`` and ``set`` methods,
13041318
as well as the legacy ``defaults=`` keyword argument handling.
13051319

1320+
.. versionchanged:: 3.2
1321+
*allow_no_value*, *delimiters*, *comment_prefixes*, *strict*,
1322+
*empty_lines_in_values*, *default_section* and *interpolation* were
1323+
added.
1324+
1325+
.. versionchanged:: 3.5
1326+
The *converters* argument was added.
1327+
13061328
.. versionchanged:: 3.8
13071329
The default *dict_type* is :class:`dict`, since it now preserves
13081330
insertion order.
13091331

1332+
.. versionchanged:: 3.13
1333+
The *allow_unnamed_section* argument was added.
1334+
13101335
.. note::
13111336
Consider using :class:`ConfigParser` instead which checks types of
13121337
the values to be stored internally. If you don't want interpolation, you

Doc/library/math.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ Number-theoretic and representation functions
406406

407407
Roughly equivalent to::
408408

409-
sum(itertools.starmap(operator.mul, zip(p, q, strict=True)))
409+
sum(map(operator.mul, p, q, strict=True))
410410

411411
For float and mixed int/float inputs, the intermediate products
412412
and sums are computed with extended precision.

Doc/library/os.rst

+24-9
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,6 @@ process and user.
193193
to the environment made after this time are not reflected in :data:`os.environ`,
194194
except for changes made by modifying :data:`os.environ` directly.
195195

196-
The :meth:`!os.environ.refresh` method updates :data:`os.environ` with
197-
changes to the environment made by :func:`os.putenv`, by
198-
:func:`os.unsetenv`, or made outside Python in the same process.
199-
200196
This mapping may be used to modify the environment as well as query the
201197
environment. :func:`putenv` will be called automatically when the mapping
202198
is modified.
@@ -226,12 +222,13 @@ process and user.
226222
:data:`os.environ`, and when one of the :meth:`pop` or :meth:`clear` methods is
227223
called.
228224

225+
.. seealso::
226+
227+
The :func:`os.reload_environ` function.
228+
229229
.. versionchanged:: 3.9
230230
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
231231

232-
.. versionchanged:: 3.14
233-
Added the :meth:`!os.environ.refresh` method.
234-
235232

236233
.. data:: environb
237234

@@ -249,6 +246,24 @@ process and user.
249246
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
250247

251248

249+
.. function:: reload_environ()
250+
251+
The :data:`os.environ` and :data:`os.environb` mappings are a cache of
252+
environment variables at the time that Python started.
253+
As such, changes to the current process environment are not reflected
254+
if made outside Python, or by :func:`os.putenv` or :func:`os.unsetenv`.
255+
Use :func:`!os.reload_environ` to update :data:`os.environ` and :data:`os.environb`
256+
with any such changes to the current process environment.
257+
258+
.. warning::
259+
This function is not thread-safe. Calling it while the environment is
260+
being modified in an other thread is an undefined behavior. Reading from
261+
:data:`os.environ` or :data:`os.environb`, or calling :func:`os.getenv`
262+
while reloading, may return an empty result.
263+
264+
.. versionadded:: next
265+
266+
252267
.. function:: chdir(path)
253268
fchdir(fd)
254269
getcwd()
@@ -568,7 +583,7 @@ process and user.
568583
of :data:`os.environ`. This also applies to :func:`getenv` and :func:`getenvb`, which
569584
respectively use :data:`os.environ` and :data:`os.environb` in their implementations.
570585

571-
See also the :data:`os.environ.refresh() <os.environ>` method.
586+
See also the :func:`os.reload_environ` function.
572587

573588
.. note::
574589

@@ -818,7 +833,7 @@ process and user.
818833
don't update :data:`os.environ`, so it is actually preferable to delete items of
819834
:data:`os.environ`.
820835

821-
See also the :data:`os.environ.refresh() <os.environ>` method.
836+
See also the :func:`os.reload_environ` function.
822837

823838
.. audit-event:: os.unsetenv key os.unsetenv
824839

Doc/whatsnew/3.14.rst

+4-3
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,10 @@ operator
365365
os
366366
--
367367

368-
* Add the :data:`os.environ.refresh() <os.environ>` method to update
369-
:data:`os.environ` with changes to the environment made by :func:`os.putenv`,
370-
by :func:`os.unsetenv`, or made outside Python in the same process.
368+
* Add the :func:`os.reload_environ` function to update :data:`os.environ` and
369+
:data:`os.environb` with changes to the environment made by
370+
:func:`os.putenv`, by :func:`os.unsetenv`, or made outside Python in the
371+
same process.
371372
(Contributed by Victor Stinner in :gh:`120057`.)
372373

373374

Include/internal/pycore_typeobject.h

+1
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ extern PyObject* _PyType_GetFullyQualifiedName(PyTypeObject *type, char sep);
243243
// self->tp_flags = (self->tp_flags & ~mask) | flags;
244244
extern void _PyType_SetFlags(PyTypeObject *self, unsigned long mask,
245245
unsigned long flags);
246+
extern int _PyType_AddMethod(PyTypeObject *, PyMethodDef *);
246247

247248
// Like _PyType_SetFlags(), but apply the operation to self and any of its
248249
// subclasses without Py_TPFLAGS_IMMUTABLETYPE set.

Lib/multiprocessing/managers.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import threading
1919
import signal
2020
import array
21+
import collections.abc
2122
import queue
2223
import time
2324
import types
@@ -1167,8 +1168,9 @@ def __imul__(self, value):
11671168

11681169
__class_getitem__ = classmethod(types.GenericAlias)
11691170

1171+
collections.abc.MutableSequence.register(BaseListProxy)
11701172

1171-
_BaseDictProxy = MakeProxyType('DictProxy', (
1173+
_BaseDictProxy = MakeProxyType('_BaseDictProxy', (
11721174
'__contains__', '__delitem__', '__getitem__', '__ior__', '__iter__',
11731175
'__len__', '__or__', '__reversed__', '__ror__',
11741176
'__setitem__', 'clear', 'copy', 'fromkeys', 'get', 'items',
@@ -1184,6 +1186,8 @@ def __ior__(self, value):
11841186

11851187
__class_getitem__ = classmethod(types.GenericAlias)
11861188

1189+
collections.abc.MutableMapping.register(_BaseDictProxy)
1190+
11871191
ArrayProxy = MakeProxyType('ArrayProxy', (
11881192
'__len__', '__getitem__', '__setitem__'
11891193
))

Lib/os.py

+14-11
Original file line numberDiff line numberDiff line change
@@ -765,17 +765,6 @@ def __ror__(self, other):
765765
new.update(self)
766766
return new
767767

768-
if _exists("_create_environ"):
769-
def refresh(self):
770-
data = _create_environ()
771-
if name == 'nt':
772-
data = {self.encodekey(key): value
773-
for key, value in data.items()}
774-
775-
# modify in-place to keep os.environb in sync
776-
self._data.clear()
777-
self._data.update(data)
778-
779768
def _create_environ_mapping():
780769
if name == 'nt':
781770
# Where Env Var Names Must Be UPPERCASE
@@ -810,6 +799,20 @@ def decode(value):
810799
del _create_environ_mapping
811800

812801

802+
if _exists("_create_environ"):
803+
def reload_environ():
804+
data = _create_environ()
805+
if name == 'nt':
806+
encodekey = environ.encodekey
807+
data = {encodekey(key): value
808+
for key, value in data.items()}
809+
810+
# modify in-place to keep os.environb in sync
811+
env_data = environ._data
812+
env_data.clear()
813+
env_data.update(data)
814+
815+
813816
def getenv(key, default=None):
814817
"""Get an environment variable, return None if it doesn't exist.
815818
The optional second argument can specify an alternate default.

Lib/pathlib/_local.py

+27-14
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,31 @@ def _parse_path(cls, path):
274274
root = sep
275275
return drv, root, [x for x in rel.split(sep) if x and x != '.']
276276

277+
@classmethod
278+
def _parse_pattern(cls, pattern):
279+
"""Parse a glob pattern to a list of parts. This is much like
280+
_parse_path, except:
281+
282+
- Rather than normalizing and returning the drive and root, we raise
283+
NotImplementedError if either are present.
284+
- If the path has no real parts, we raise ValueError.
285+
- If the path ends in a slash, then a final empty part is added.
286+
"""
287+
drv, root, rel = cls.parser.splitroot(pattern)
288+
if root or drv:
289+
raise NotImplementedError("Non-relative patterns are unsupported")
290+
sep = cls.parser.sep
291+
altsep = cls.parser.altsep
292+
if altsep:
293+
rel = rel.replace(altsep, sep)
294+
parts = [x for x in rel.split(sep) if x and x != '.']
295+
if not parts:
296+
raise ValueError(f"Unacceptable pattern: {str(pattern)!r}")
297+
elif rel.endswith(sep):
298+
# GH-65238: preserve trailing slash in glob patterns.
299+
parts.append('')
300+
return parts
301+
277302
@property
278303
def _raw_path(self):
279304
"""The joined but unnormalized path."""
@@ -641,17 +666,7 @@ def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=False):
641666
kind, including directories) matching the given relative pattern.
642667
"""
643668
sys.audit("pathlib.Path.glob", self, pattern)
644-
if not isinstance(pattern, PurePath):
645-
pattern = self.with_segments(pattern)
646-
if pattern.anchor:
647-
raise NotImplementedError("Non-relative patterns are unsupported")
648-
parts = pattern._tail.copy()
649-
if not parts:
650-
raise ValueError("Unacceptable pattern: {!r}".format(pattern))
651-
raw = pattern._raw_path
652-
if raw[-1] in (self.parser.sep, self.parser.altsep):
653-
# GH-65238: pathlib doesn't preserve trailing slash. Add it back.
654-
parts.append('')
669+
parts = self._parse_pattern(pattern)
655670
select = self._glob_selector(parts[::-1], case_sensitive, recurse_symlinks)
656671
root = str(self)
657672
paths = select(root)
@@ -672,9 +687,7 @@ def rglob(self, pattern, *, case_sensitive=None, recurse_symlinks=False):
672687
this subtree.
673688
"""
674689
sys.audit("pathlib.Path.rglob", self, pattern)
675-
if not isinstance(pattern, PurePath):
676-
pattern = self.with_segments(pattern)
677-
pattern = '**' / pattern
690+
pattern = self.parser.join('**', pattern)
678691
return self.glob(pattern, case_sensitive=case_sensitive, recurse_symlinks=recurse_symlinks)
679692

680693
def walk(self, top_down=True, on_error=None, follow_symlinks=False):

Lib/test/_test_multiprocessing.py

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import functools
1717
import signal
1818
import array
19+
import collections.abc
1920
import socket
2021
import random
2122
import logging
@@ -2331,6 +2332,10 @@ def test_list(self):
23312332
a.append('hello')
23322333
self.assertEqual(f[0][:], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'hello'])
23332334

2335+
def test_list_isinstance(self):
2336+
a = self.list()
2337+
self.assertIsInstance(a, collections.abc.MutableSequence)
2338+
23342339
def test_list_iter(self):
23352340
a = self.list(list(range(10)))
23362341
it = iter(a)
@@ -2371,6 +2376,10 @@ def test_dict(self):
23712376
self.assertEqual(sorted(d.values()), [chr(i) for i in indices])
23722377
self.assertEqual(sorted(d.items()), [(i, chr(i)) for i in indices])
23732378

2379+
def test_dict_isinstance(self):
2380+
a = self.dict()
2381+
self.assertIsInstance(a, collections.abc.MutableMapping)
2382+
23742383
def test_dict_iter(self):
23752384
d = self.dict()
23762385
indices = list(range(65, 70))

Lib/test/test_os.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -1298,8 +1298,8 @@ def test_ror_operator(self):
12981298
self._test_underlying_process_env('_A_', '')
12991299
self._test_underlying_process_env(overridden_key, original_value)
13001300

1301-
def test_refresh(self):
1302-
# Test os.environ.refresh()
1301+
def test_reload_environ(self):
1302+
# Test os.reload_environ()
13031303
has_environb = hasattr(os, 'environb')
13041304

13051305
# Test with putenv() which doesn't update os.environ
@@ -1309,7 +1309,7 @@ def test_refresh(self):
13091309
if has_environb:
13101310
self.assertEqual(os.environb[b'test_env'], b'python_value')
13111311

1312-
os.environ.refresh()
1312+
os.reload_environ()
13131313
self.assertEqual(os.environ['test_env'], 'new_value')
13141314
if has_environb:
13151315
self.assertEqual(os.environb[b'test_env'], b'new_value')
@@ -1320,28 +1320,28 @@ def test_refresh(self):
13201320
if has_environb:
13211321
self.assertEqual(os.environb[b'test_env'], b'new_value')
13221322

1323-
os.environ.refresh()
1323+
os.reload_environ()
13241324
self.assertNotIn('test_env', os.environ)
13251325
if has_environb:
13261326
self.assertNotIn(b'test_env', os.environb)
13271327

13281328
if has_environb:
1329-
# test os.environb.refresh() with putenv()
1329+
# test reload_environ() on os.environb with putenv()
13301330
os.environb[b'test_env'] = b'python_value2'
13311331
os.putenv("test_env", "new_value2")
13321332
self.assertEqual(os.environb[b'test_env'], b'python_value2')
13331333
self.assertEqual(os.environ['test_env'], 'python_value2')
13341334

1335-
os.environb.refresh()
1335+
os.reload_environ()
13361336
self.assertEqual(os.environb[b'test_env'], b'new_value2')
13371337
self.assertEqual(os.environ['test_env'], 'new_value2')
13381338

1339-
# test os.environb.refresh() with unsetenv()
1339+
# test reload_environ() on os.environb with unsetenv()
13401340
os.unsetenv('test_env')
13411341
self.assertEqual(os.environb[b'test_env'], b'new_value2')
13421342
self.assertEqual(os.environ['test_env'], 'new_value2')
13431343

1344-
os.environb.refresh()
1344+
os.reload_environ()
13451345
self.assertNotIn(b'test_env', os.environb)
13461346
self.assertNotIn('test_env', os.environ)
13471347

0 commit comments

Comments
 (0)