Skip to content

Commit 18a6511

Browse files
committed
Merge branch 'main' into deopts-with-ip
2 parents 0a093fd + a519b87 commit 18a6511

Some content is hidden

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

64 files changed

+1372
-785
lines changed

Doc/c-api/dict.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,33 @@ Dictionary Objects
173173
174174
.. versionadded:: 3.4
175175
176+
177+
.. c:function:: int PyDict_Pop(PyObject *p, PyObject *key, PyObject **result)
178+
179+
Remove *key* from dictionary *p* and optionally return the removed value.
180+
Do not raise :exc:`KeyError` if the key missing.
181+
182+
- If the key is present, set *\*result* to a new reference to the removed
183+
value if *result* is not ``NULL``, and return ``1``.
184+
- If the key is missing, set *\*result* to ``NULL`` if *result* is not
185+
``NULL``, and return ``0``.
186+
- On error, raise an exception and return ``-1``.
187+
188+
This is similar to :meth:`dict.pop`, but without the default value and
189+
not raising :exc:`KeyError` if the key missing.
190+
191+
.. versionadded:: 3.13
192+
193+
194+
.. c:function:: int PyDict_PopString(PyObject *p, const char *key, PyObject **result)
195+
196+
Similar to :c:func:`PyDict_Pop`, but *key* is specified as a
197+
:c:expr:`const char*` UTF-8 encoded bytes string, rather than a
198+
:c:expr:`PyObject*`.
199+
200+
.. versionadded:: 3.13
201+
202+
176203
.. c:function:: PyObject* PyDict_Items(PyObject *p)
177204
178205
Return a :c:type:`PyListObject` containing all the items from the dictionary.

Doc/c-api/list.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,30 @@ List Objects
128128
list is not supported.
129129
130130
131+
.. c:function:: int PyList_Extend(PyObject *list, PyObject *iterable)
132+
133+
Extend *list* with the contents of *iterable*. This is the same as
134+
``PyList_SetSlice(list, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, iterable)``
135+
and analogous to ``list.extend(iterable)`` or ``list += iterable``.
136+
137+
Raise an exception and return ``-1`` if *list* is not a :class:`list`
138+
object. Return 0 on success.
139+
140+
.. versionadded:: 3.13
141+
142+
143+
.. c:function:: int PyList_Clear(PyObject *list)
144+
145+
Remove all items from *list*. This is the same as
146+
``PyList_SetSlice(list, 0, PY_SSIZE_T_MAX, NULL)`` and analogous to
147+
``list.clear()`` or ``del list[:]``.
148+
149+
Raise an exception and return ``-1`` if *list* is not a :class:`list`
150+
object. Return 0 on success.
151+
152+
.. versionadded:: 3.13
153+
154+
131155
.. c:function:: int PyList_Sort(PyObject *list)
132156
133157
Sort the items of *list* in place. Return ``0`` on success, ``-1`` on

Doc/library/glob.rst

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ unlike :func:`fnmatch.fnmatch` or :func:`pathlib.Path.glob`.
3434
For a literal match, wrap the meta-characters in brackets.
3535
For example, ``'[?]'`` matches the character ``'?'``.
3636

37-
38-
.. seealso::
39-
The :mod:`pathlib` module offers high-level path objects.
37+
The :mod:`glob` module defines the following functions:
4038

4139

4240
.. function:: glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, \
@@ -117,7 +115,48 @@ For example, ``'[?]'`` matches the character ``'?'``.
117115
.. versionadded:: 3.4
118116

119117

120-
For example, consider a directory containing the following files:
118+
.. function:: translate(pathname, *, recursive=False, include_hidden=False, seps=None)
119+
120+
Convert the given path specification to a regular expression for use with
121+
:func:`re.match`. The path specification can contain shell-style wildcards.
122+
123+
For example:
124+
125+
>>> import glob, re
126+
>>>
127+
>>> regex = glob.translate('**/*.txt', recursive=True, include_hidden=True)
128+
>>> regex
129+
'(?s:(?:.+/)?[^/]*\\.txt)\\Z'
130+
>>> reobj = re.compile(regex)
131+
>>> reobj.match('foo/bar/baz.txt')
132+
<re.Match object; span=(0, 15), match='foo/bar/baz.txt'>
133+
134+
Path separators and segments are meaningful to this function, unlike
135+
:func:`fnmatch.translate`. By default wildcards do not match path
136+
separators, and ``*`` pattern segments match precisely one path segment.
137+
138+
If *recursive* is true, the pattern segment "``**``" will match any number
139+
of path segments. If "``**``" occurs in any position other than a full
140+
pattern segment, :exc:`ValueError` is raised.
141+
142+
If *include_hidden* is true, wildcards can match path segments that start
143+
with a dot (``.``).
144+
145+
A sequence of path separators may be supplied to the *seps* argument. If
146+
not given, :data:`os.sep` and :data:`~os.altsep` (if available) are used.
147+
148+
.. seealso::
149+
150+
:meth:`pathlib.PurePath.match` and :meth:`pathlib.Path.glob` methods,
151+
which call this function to implement pattern matching and globbing.
152+
153+
.. versionadded:: 3.13
154+
155+
156+
Examples
157+
--------
158+
159+
Consider a directory containing the following files:
121160
:file:`1.gif`, :file:`2.txt`, :file:`card.gif` and a subdirectory :file:`sub`
122161
which contains only the file :file:`3.txt`. :func:`glob` will produce
123162
the following results. Notice how any leading components of the path are
@@ -146,6 +185,7 @@ default. For example, consider a directory containing :file:`card.gif` and
146185
['.card.gif']
147186

148187
.. seealso::
188+
The :mod:`fnmatch` module offers shell-style filename (not path) expansion.
149189

150-
Module :mod:`fnmatch`
151-
Shell-style filename (not path) expansion
190+
.. seealso::
191+
The :mod:`pathlib` module offers high-level path objects.

Doc/library/stdtypes.rst

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4755,14 +4755,17 @@ support membership tests:
47554755

47564756
.. versionadded:: 3.10
47574757

4758-
Keys views are set-like since their entries are unique and :term:`hashable`. If all
4759-
values are hashable, so that ``(key, value)`` pairs are unique and hashable,
4760-
then the items view is also set-like. (Values views are not treated as set-like
4758+
Keys views are set-like since their entries are unique and :term:`hashable`.
4759+
Items views also have set-like operations since the (key, value) pairs
4760+
are unique and the keys are hashable.
4761+
If all values in an items view are hashable as well,
4762+
then the items view can interoperate with other sets.
4763+
(Values views are not treated as set-like
47614764
since the entries are generally not unique.) For set-like views, all of the
47624765
operations defined for the abstract base class :class:`collections.abc.Set` are
47634766
available (for example, ``==``, ``<``, or ``^``). While using set operators,
4764-
set-like views accept any iterable as the other operand, unlike sets which only
4765-
accept sets as the input.
4767+
set-like views accept any iterable as the other operand,
4768+
unlike sets which only accept sets as the input.
47664769

47674770
An example of dictionary view usage::
47684771

Doc/whatsnew/3.13.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ doctest
183183
:attr:`doctest.TestResults.skipped` attributes.
184184
(Contributed by Victor Stinner in :gh:`108794`.)
185185

186+
glob
187+
----
188+
189+
* Add :func:`glob.translate` function that converts a path specification with
190+
shell-style wildcards to a regular expression.
191+
(Contributed by Barney Gale in :gh:`72904`.)
192+
186193
io
187194
--
188195

@@ -1164,6 +1171,16 @@ New Features
11641171
:c:func:`PyErr_WriteUnraisable`, but allow to customize the warning mesage.
11651172
(Contributed by Serhiy Storchaka in :gh:`108082`.)
11661173

1174+
* Add :c:func:`PyList_Extend` and :c:func:`PyList_Clear` functions: similar to
1175+
Python ``list.extend()`` and ``list.clear()`` methods.
1176+
(Contributed by Victor Stinner in :gh:`111138`.)
1177+
1178+
* Add :c:func:`PyDict_Pop` and :c:func:`PyDict_PopString` functions: remove a
1179+
key from a dictionary and optionally return the removed value. This is
1180+
similar to :meth:`dict.pop`, but without the default value and not raising
1181+
:exc:`KeyError` if the key missing.
1182+
(Contributed by Stefan Behnel and Victor Stinner in :gh:`111262`.)
1183+
11671184

11681185
Porting to Python 3.13
11691186
----------------------

Include/cpython/compile.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,3 @@ typedef struct {
6868
#define PY_INVALID_STACK_EFFECT INT_MAX
6969
PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg);
7070
PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump);
71-
72-
PyAPI_FUNC(int) PyUnstable_OpcodeIsValid(int opcode);
73-
PyAPI_FUNC(int) PyUnstable_OpcodeHasArg(int opcode);
74-
PyAPI_FUNC(int) PyUnstable_OpcodeHasConst(int opcode);
75-
PyAPI_FUNC(int) PyUnstable_OpcodeHasName(int opcode);
76-
PyAPI_FUNC(int) PyUnstable_OpcodeHasJump(int opcode);
77-
PyAPI_FUNC(int) PyUnstable_OpcodeHasFree(int opcode);
78-
PyAPI_FUNC(int) PyUnstable_OpcodeHasLocal(int opcode);
79-
PyAPI_FUNC(int) PyUnstable_OpcodeHasExc(int opcode);
80-
81-
PyAPI_FUNC(PyObject*) PyUnstable_GetUnaryIntrinsicName(int index);
82-
PyAPI_FUNC(PyObject*) PyUnstable_GetBinaryIntrinsicName(int index);

Include/cpython/dictobject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ static inline Py_ssize_t PyDict_GET_SIZE(PyObject *op) {
4646

4747
PyAPI_FUNC(int) PyDict_ContainsString(PyObject *mp, const char *key);
4848

49+
PyAPI_FUNC(int) PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result);
50+
PyAPI_FUNC(int) PyDict_PopString(PyObject *dict, const char *key, PyObject **result);
4951
PyAPI_FUNC(PyObject *) _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value);
5052

5153
/* Dictionary watchers */

Include/cpython/listobject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,6 @@ PyList_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
4444
}
4545
#define PyList_SET_ITEM(op, index, value) \
4646
PyList_SET_ITEM(_PyObject_CAST(op), (index), _PyObject_CAST(value))
47+
48+
PyAPI_FUNC(int) PyList_Extend(PyObject *self, PyObject *iterable);
49+
PyAPI_FUNC(int) PyList_Clear(PyObject *self);

Include/internal/pycore_compile.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ int _PyCompile_EnsureArrayLargeEnough(
102102

103103
int _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj);
104104

105+
106+
// Export for '_opcode' extention module
107+
PyAPI_FUNC(int) _PyCompile_OpcodeIsValid(int opcode);
108+
PyAPI_FUNC(int) _PyCompile_OpcodeHasArg(int opcode);
109+
PyAPI_FUNC(int) _PyCompile_OpcodeHasConst(int opcode);
110+
PyAPI_FUNC(int) _PyCompile_OpcodeHasName(int opcode);
111+
PyAPI_FUNC(int) _PyCompile_OpcodeHasJump(int opcode);
112+
PyAPI_FUNC(int) _PyCompile_OpcodeHasFree(int opcode);
113+
PyAPI_FUNC(int) _PyCompile_OpcodeHasLocal(int opcode);
114+
PyAPI_FUNC(int) _PyCompile_OpcodeHasExc(int opcode);
115+
116+
PyAPI_FUNC(PyObject*) _PyCompile_GetUnaryIntrinsicName(int index);
117+
PyAPI_FUNC(PyObject*) _PyCompile_GetBinaryIntrinsicName(int index);
118+
105119
/* Access compiler internals for unit testing */
106120

107121
// Export for '_testinternalcapi' shared extension

Include/internal/pycore_dict.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,11 @@ extern PyObject *_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *);
116116
extern int _PyDict_SetItem_Take2(PyDictObject *op, PyObject *key, PyObject *value);
117117
extern int _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, PyObject *name, PyObject *value);
118118

119-
extern PyObject *_PyDict_Pop_KnownHash(PyObject *, PyObject *, Py_hash_t, PyObject *);
119+
extern int _PyDict_Pop_KnownHash(
120+
PyDictObject *dict,
121+
PyObject *key,
122+
Py_hash_t hash,
123+
PyObject **result);
120124

121125
#define DKIX_EMPTY (-1)
122126
#define DKIX_DUMMY (-2) /* Used internally */

Lib/fnmatch.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ def translate(pat):
7878
"""
7979

8080
STAR = object()
81+
parts = _translate(pat, STAR, '.')
82+
return _join_translated_parts(parts, STAR)
83+
84+
85+
def _translate(pat, STAR, QUESTION_MARK):
8186
res = []
8287
add = res.append
8388
i, n = 0, len(pat)
@@ -89,7 +94,7 @@ def translate(pat):
8994
if (not res) or res[-1] is not STAR:
9095
add(STAR)
9196
elif c == '?':
92-
add('.')
97+
add(QUESTION_MARK)
9398
elif c == '[':
9499
j = i
95100
if j < n and pat[j] == '!':
@@ -146,9 +151,11 @@ def translate(pat):
146151
else:
147152
add(re.escape(c))
148153
assert i == n
154+
return res
155+
149156

157+
def _join_translated_parts(inp, STAR):
150158
# Deal with STARs.
151-
inp = res
152159
res = []
153160
add = res.append
154161
i, n = 0, len(inp)

Lib/glob.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,63 @@ def escape(pathname):
249249

250250

251251
_dir_open_flags = os.O_RDONLY | getattr(os, 'O_DIRECTORY', 0)
252+
253+
254+
def translate(pat, *, recursive=False, include_hidden=False, seps=None):
255+
"""Translate a pathname with shell wildcards to a regular expression.
256+
257+
If `recursive` is true, the pattern segment '**' will match any number of
258+
path segments; if '**' appears outside its own segment, ValueError will be
259+
raised.
260+
261+
If `include_hidden` is true, wildcards can match path segments beginning
262+
with a dot ('.').
263+
264+
If a sequence of separator characters is given to `seps`, they will be
265+
used to split the pattern into segments and match path separators. If not
266+
given, os.path.sep and os.path.altsep (where available) are used.
267+
"""
268+
if not seps:
269+
if os.path.altsep:
270+
seps = (os.path.sep, os.path.altsep)
271+
else:
272+
seps = os.path.sep
273+
escaped_seps = ''.join(map(re.escape, seps))
274+
any_sep = f'[{escaped_seps}]' if len(seps) > 1 else escaped_seps
275+
not_sep = f'[^{escaped_seps}]'
276+
if include_hidden:
277+
one_last_segment = f'{not_sep}+'
278+
one_segment = f'{one_last_segment}{any_sep}'
279+
any_segments = f'(?:.+{any_sep})?'
280+
any_last_segments = '.*'
281+
else:
282+
one_last_segment = f'[^{escaped_seps}.]{not_sep}*'
283+
one_segment = f'{one_last_segment}{any_sep}'
284+
any_segments = f'(?:{one_segment})*'
285+
any_last_segments = f'{any_segments}(?:{one_last_segment})?'
286+
287+
results = []
288+
parts = re.split(any_sep, pat)
289+
last_part_idx = len(parts) - 1
290+
for idx, part in enumerate(parts):
291+
if part == '*':
292+
results.append(one_segment if idx < last_part_idx else one_last_segment)
293+
continue
294+
if recursive:
295+
if part == '**':
296+
if idx < last_part_idx:
297+
if parts[idx + 1] != '**':
298+
results.append(any_segments)
299+
else:
300+
results.append(any_last_segments)
301+
continue
302+
elif '**' in part:
303+
raise ValueError("Invalid pattern: '**' can only be an entire path component")
304+
if part:
305+
if not include_hidden and part[0] in '*?':
306+
results.append(r'(?!\.)')
307+
results.extend(fnmatch._translate(part, f'{not_sep}*', not_sep))
308+
if idx < last_part_idx:
309+
results.append(any_sep)
310+
res = ''.join(results)
311+
return fr'(?s:{res})\Z'

0 commit comments

Comments
 (0)