Skip to content

Commit 16a995d

Browse files
committed
Merge branch 'main' into docs/pep750-first-pass
2 parents 64c6758 + 2bdd503 commit 16a995d

41 files changed

Lines changed: 274 additions & 131 deletions

Some content is hidden

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

Doc/library/codecs.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ any codec:
5353
:exc:`UnicodeDecodeError`). Refer to :ref:`codec-base-classes` for more
5454
information on codec error handling.
5555

56+
.. function:: charmap_build(string)
57+
58+
Return a mapping suitable for encoding with a custom single-byte encoding.
59+
Given a :class:`str` *string* of up to 256 characters representing a
60+
decoding table, returns either a compact internal mapping object
61+
``EncodingMap`` or a :class:`dictionary <dict>` mapping character ordinals
62+
to byte values. Raises a :exc:`TypeError` on invalid input.
63+
5664
The full details for each codec can also be looked up directly:
5765

5866
.. function:: lookup(encoding, /)

Doc/library/csv.rst

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ The :mod:`csv` module defines the following functions:
5353
.. index::
5454
single: universal newlines; csv.reader function
5555

56-
.. function:: reader(csvfile, dialect='excel', **fmtparams)
56+
.. function:: reader(csvfile, /, dialect='excel', **fmtparams)
5757

5858
Return a :ref:`reader object <reader-objects>` that will process
5959
lines from the given *csvfile*. A csvfile must be an iterable of
@@ -84,7 +84,7 @@ The :mod:`csv` module defines the following functions:
8484
Spam, Lovely Spam, Wonderful Spam
8585

8686

87-
.. function:: writer(csvfile, dialect='excel', **fmtparams)
87+
.. function:: writer(csvfile, /, dialect='excel', **fmtparams)
8888

8989
Return a writer object responsible for converting the user's data into delimited
9090
strings on the given file-like object. *csvfile* can be any object with a
@@ -323,8 +323,8 @@ The :mod:`csv` module defines the following constants:
323323
.. data:: QUOTE_MINIMAL
324324

325325
Instructs :class:`writer` objects to only quote those fields which contain
326-
special characters such as *delimiter*, *quotechar* or any of the characters in
327-
*lineterminator*.
326+
special characters such as *delimiter*, *quotechar*, ``'\r'``, ``'\n'``
327+
or any of the characters in *lineterminator*.
328328

329329

330330
.. data:: QUOTE_NONNUMERIC
@@ -342,10 +342,13 @@ The :mod:`csv` module defines the following constants:
342342

343343
.. data:: QUOTE_NONE
344344

345-
Instructs :class:`writer` objects to never quote fields. When the current
346-
*delimiter* occurs in output data it is preceded by the current *escapechar*
347-
character. If *escapechar* is not set, the writer will raise :exc:`Error` if
345+
Instructs :class:`writer` objects to never quote fields.
346+
When the current *delimiter*, *quotechar*, *escapechar*, ``'\r'``, ``'\n'``
347+
or any of the characters in *lineterminator* occurs in output data
348+
it is preceded by the current *escapechar* character.
349+
If *escapechar* is not set, the writer will raise :exc:`Error` if
348350
any characters that require escaping are encountered.
351+
Set *quotechar* to ``None`` to prevent its escaping.
349352

350353
Instructs :class:`reader` objects to perform no special processing of quote characters.
351354

@@ -414,9 +417,16 @@ Dialects support the following attributes:
414417

415418
.. attribute:: Dialect.escapechar
416419

417-
A one-character string used by the writer to escape the *delimiter* if *quoting*
418-
is set to :const:`QUOTE_NONE` and the *quotechar* if *doublequote* is
419-
:const:`False`. On reading, the *escapechar* removes any special meaning from
420+
A one-character string used by the writer to escape characters that
421+
require escaping:
422+
423+
* the *delimiter*, the *quotechar*, ``'\r'``, ``'\n'`` and any of the
424+
characters in *lineterminator* are escaped if *quoting* is set to
425+
:const:`QUOTE_NONE`;
426+
* the *quotechar* is escaped if *doublequote* is :const:`False`;
427+
* the *escapechar* itself.
428+
429+
On reading, the *escapechar* removes any special meaning from
420430
the following character. It defaults to :const:`None`, which disables escaping.
421431

422432
.. versionchanged:: 3.11
@@ -436,9 +446,12 @@ Dialects support the following attributes:
436446

437447
.. attribute:: Dialect.quotechar
438448

439-
A one-character string used to quote fields containing special characters, such
440-
as the *delimiter* or *quotechar*, or which contain new-line characters. It
441-
defaults to ``'"'``.
449+
A one-character string used to quote fields containing special characters,
450+
such as the *delimiter* or the *quotechar*, or which contain new-line
451+
characters (``'\r'``, ``'\n'`` or any of the characters in *lineterminator*).
452+
It defaults to ``'"'``.
453+
Can be set to ``None`` to prevent escaping ``'"'`` if *quoting* is set
454+
to :const:`QUOTE_NONE`.
442455

443456
.. versionchanged:: 3.11
444457
An empty *quotechar* is not allowed.
@@ -447,7 +460,8 @@ Dialects support the following attributes:
447460

448461
Controls when quotes should be generated by the writer and recognised by the
449462
reader. It can take on any of the :ref:`QUOTE_\* constants <csv-constants>`
450-
and defaults to :const:`QUOTE_MINIMAL`.
463+
and defaults to :const:`QUOTE_MINIMAL` if *quotechar* is not ``None``,
464+
and :const:`QUOTE_NONE` otherwise.
451465

452466

453467
.. attribute:: Dialect.skipinitialspace

Doc/library/venv.rst

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -105,36 +105,52 @@ The command, if run with ``-h``, will show the available options::
105105

106106
Creates virtual Python environments in one or more target directories.
107107

108-
positional arguments:
109-
ENV_DIR A directory to create the environment in.
110-
111-
options:
112-
-h, --help show this help message and exit
113-
--system-site-packages
114-
Give the virtual environment access to the system
115-
site-packages dir.
116-
--symlinks Try to use symlinks rather than copies, when
117-
symlinks are not the default for the platform.
118-
--copies Try to use copies rather than symlinks, even when
119-
symlinks are the default for the platform.
120-
--clear Delete the contents of the environment directory
121-
if it already exists, before environment creation.
122-
--upgrade Upgrade the environment directory to use this
123-
version of Python, assuming Python has been
124-
upgraded in-place.
125-
--without-pip Skips installing or upgrading pip in the virtual
126-
environment (pip is bootstrapped by default)
127-
--prompt PROMPT Provides an alternative prompt prefix for this
128-
environment.
129-
--upgrade-deps Upgrade core dependencies (pip) to the latest
130-
version in PyPI
131-
--without-scm-ignore-files
132-
Skips adding SCM ignore files to the environment
133-
directory (Git is supported by default).
134-
135108
Once an environment has been created, you may wish to activate it, e.g. by
136109
sourcing an activate script in its bin directory.
137110

111+
.. _venv-cli:
112+
.. program:: venv
113+
114+
.. option:: ENV_DIR
115+
116+
A required argument specifying the directory to create the environment in.
117+
118+
.. option:: --system-site-packages
119+
120+
Give the virtual environment access to the system site-packages directory.
121+
122+
.. option:: --symlinks
123+
124+
Try to use symlinks rather than copies, when symlinks are not the default for the platform.
125+
126+
.. option:: --copies
127+
128+
Try to use copies rather than symlinks, even when symlinks are the default for the platform.
129+
130+
.. option:: --clear
131+
132+
Delete the contents of the environment directory if it already exists, before environment creation.
133+
134+
.. option:: --upgrade
135+
136+
Upgrade the environment directory to use this version of Python, assuming Python has been upgraded in-place.
137+
138+
.. option:: --without-pip
139+
140+
Skips installing or upgrading pip in the virtual environment (pip is bootstrapped by default).
141+
142+
.. option:: --prompt <PROMPT>
143+
144+
Provides an alternative prompt prefix for this environment.
145+
146+
.. option:: --upgrade-deps
147+
148+
Upgrade core dependencies (pip) to the latest version in PyPI.
149+
150+
.. option:: --without-scm-ignore-files
151+
152+
Skips adding SCM ignore files to the environment directory (Git is supported by default).
153+
138154

139155
.. versionchanged:: 3.4
140156
Installs pip by default, added the ``--without-pip`` and ``--copies``

Include/internal/pycore_weakref.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ extern "C" {
2929
PyMutex_LockFlags(wr->weakrefs_lock, _Py_LOCK_DONT_DETACH)
3030
#define UNLOCK_WEAKREFS_FOR_WR(wr) PyMutex_Unlock(wr->weakrefs_lock)
3131

32+
#define FT_CLEAR_WEAKREFS(obj, weakref_list) \
33+
do { \
34+
assert(Py_REFCNT(obj) == 0); \
35+
PyObject_ClearWeakRefs(obj); \
36+
} while (0)
37+
3238
#else
3339

3440
#define LOCK_WEAKREFS(obj)
@@ -37,6 +43,14 @@ extern "C" {
3743
#define LOCK_WEAKREFS_FOR_WR(wr)
3844
#define UNLOCK_WEAKREFS_FOR_WR(wr)
3945

46+
#define FT_CLEAR_WEAKREFS(obj, weakref_list) \
47+
do { \
48+
assert(Py_REFCNT(obj) == 0); \
49+
if (weakref_list != NULL) { \
50+
PyObject_ClearWeakRefs(obj); \
51+
} \
52+
} while (0)
53+
4054
#endif
4155

4256
static inline int _is_dead(PyObject *obj)

Lib/os.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
- os.extsep is the extension separator (always '.')
1111
- os.altsep is the alternate pathname separator (None or '/')
1212
- os.pathsep is the component separator used in $PATH etc
13-
- os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')
13+
- os.linesep is the line separator in text files ('\n' or '\r\n')
1414
- os.defpath is the default search path for executables
1515
- os.devnull is the file path of the null device ('/dev/null', etc.)
1616

Lib/test/test_free_threading/test_itertools.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import unittest
22
from threading import Thread, Barrier
3-
from itertools import batched, cycle
3+
from itertools import batched, chain, cycle
44
from test.support import threading_helper
55

66

@@ -17,7 +17,7 @@ def work(it):
1717
barrier.wait()
1818
while True:
1919
try:
20-
_ = next(it)
20+
next(it)
2121
except StopIteration:
2222
break
2323

@@ -62,6 +62,34 @@ def work(it):
6262

6363
barrier.reset()
6464

65+
@threading_helper.reap_threads
66+
def test_chain(self):
67+
number_of_threads = 6
68+
number_of_iterations = 20
69+
70+
barrier = Barrier(number_of_threads)
71+
def work(it):
72+
barrier.wait()
73+
while True:
74+
try:
75+
next(it)
76+
except StopIteration:
77+
break
78+
79+
data = [(1, )] * 200
80+
for it in range(number_of_iterations):
81+
chain_iterator = chain(*data)
82+
worker_threads = []
83+
for ii in range(number_of_threads):
84+
worker_threads.append(
85+
Thread(target=work, args=[chain_iterator]))
86+
87+
with threading_helper.start_threads(worker_threads):
88+
pass
89+
90+
barrier.reset()
91+
92+
6593

6694
if __name__ == "__main__":
6795
unittest.main()
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import unittest
2+
from threading import Thread, Barrier
3+
from itertools import combinations, product
4+
from test.support import threading_helper
5+
6+
7+
threading_helper.requires_working_threading(module=True)
8+
9+
def test_concurrent_iteration(iterator, number_of_threads):
10+
barrier = Barrier(number_of_threads)
11+
def iterator_worker(it):
12+
barrier.wait()
13+
while True:
14+
try:
15+
_ = next(it)
16+
except StopIteration:
17+
return
18+
19+
worker_threads = []
20+
for ii in range(number_of_threads):
21+
worker_threads.append(
22+
Thread(target=iterator_worker, args=[iterator]))
23+
24+
with threading_helper.start_threads(worker_threads):
25+
pass
26+
27+
barrier.reset()
28+
29+
class ItertoolsThreading(unittest.TestCase):
30+
31+
@threading_helper.reap_threads
32+
def test_combinations(self):
33+
number_of_threads = 10
34+
number_of_iterations = 24
35+
36+
for it in range(number_of_iterations):
37+
iterator = combinations((1, 2, 3, 4, 5), 2)
38+
test_concurrent_iteration(iterator, number_of_threads)
39+
40+
@threading_helper.reap_threads
41+
def test_product(self):
42+
number_of_threads = 10
43+
number_of_iterations = 24
44+
45+
for it in range(number_of_iterations):
46+
iterator = product((1, 2, 3, 4, 5), (10, 20, 30))
47+
test_concurrent_iteration(iterator, number_of_threads)
48+
49+
50+
if __name__ == "__main__":
51+
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix potential :mod:`weakref` races in an object's destructor on the :term:`free threaded <free
2+
threading>` build.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make concurrent iterations over :class:`itertools.combinations` and :class:`itertools.product` safe under free-threading.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make concurrent iterations over :class:`itertools.chain` safe under :term:`free threading`.

0 commit comments

Comments
 (0)