Skip to content

Commit 6c61822

Browse files
committed
Merge branch 'main' into pythongh-77609-glob-follow-symlinks
2 parents d3a3396 + 94f30c7 commit 6c61822

12 files changed

+95
-159
lines changed

Diff for: Include/cpython/genobject.h

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *,
7777

7878
#define PyAsyncGen_CheckExact(op) Py_IS_TYPE((op), &PyAsyncGen_Type)
7979

80+
#define PyAsyncGenASend_CheckExact(op) Py_IS_TYPE((op), &_PyAsyncGenASend_Type)
81+
8082

8183
#undef _PyGenObject_HEAD
8284

Diff for: Lib/dataclasses.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -1324,11 +1324,18 @@ def _asdict_inner(obj, dict_factory):
13241324
if type(obj) in _ATOMIC_TYPES:
13251325
return obj
13261326
elif _is_dataclass_instance(obj):
1327-
result = []
1328-
for f in fields(obj):
1329-
value = _asdict_inner(getattr(obj, f.name), dict_factory)
1330-
result.append((f.name, value))
1331-
return dict_factory(result)
1327+
# fast path for the common case
1328+
if dict_factory is dict:
1329+
return {
1330+
f.name: _asdict_inner(getattr(obj, f.name), dict)
1331+
for f in fields(obj)
1332+
}
1333+
else:
1334+
result = []
1335+
for f in fields(obj):
1336+
value = _asdict_inner(getattr(obj, f.name), dict_factory)
1337+
result.append((f.name, value))
1338+
return dict_factory(result)
13321339
elif isinstance(obj, tuple) and hasattr(obj, '_fields'):
13331340
# obj is a namedtuple. Recurse into it, but the returned
13341341
# object is another namedtuple of the same type. This is

Diff for: Lib/pathlib.py

+13-20
Original file line numberDiff line numberDiff line change
@@ -143,25 +143,21 @@ def _select_from(self, parent_path, scandir, follow_symlinks):
143143
# avoid exhausting file descriptors when globbing deep trees.
144144
with scandir(parent_path) as scandir_it:
145145
entries = list(scandir_it)
146+
except OSError:
147+
pass
148+
else:
146149
for entry in entries:
147150
if self.dironly:
148151
try:
149-
# "entry.is_dir()" can raise PermissionError
150-
# in some cases (see bpo-38894), which is not
151-
# among the errors ignored by _ignore_error()
152152
if not entry.is_dir(follow_symlinks=follow_dirlinks):
153153
continue
154-
except OSError as e:
155-
if not _ignore_error(e):
156-
raise
154+
except OSError:
157155
continue
158156
name = entry.name
159157
if self.match(name):
160158
path = parent_path._make_child_relpath(name)
161159
for p in self.successor._select_from(path, scandir, follow_symlinks):
162160
yield p
163-
except PermissionError:
164-
return
165161

166162

167163
class _RecursiveWildcardSelector(_Selector):
@@ -176,29 +172,26 @@ def _iterate_directories(self, parent_path, scandir, follow_symlinks):
176172
# avoid exhausting file descriptors when globbing deep trees.
177173
with scandir(parent_path) as scandir_it:
178174
entries = list(scandir_it)
175+
except OSError:
176+
pass
177+
else:
179178
for entry in entries:
180179
entry_is_dir = False
181180
try:
182181
entry_is_dir = entry.is_dir(follow_symlinks=follow_symlinks)
183-
except OSError as e:
184-
if not _ignore_error(e):
185-
raise
182+
except OSError:
183+
pass
186184
if entry_is_dir:
187185
path = parent_path._make_child_relpath(entry.name)
188186
for p in self._iterate_directories(path, scandir, follow_symlinks):
189187
yield p
190-
except PermissionError:
191-
return
192188

193189
def _select_from(self, parent_path, scandir, follow_symlinks):
194190
follow_dirlinks = False if follow_symlinks is None else follow_symlinks
195-
try:
196-
successor_select = self.successor._select_from
197-
for starting_point in self._iterate_directories(parent_path, scandir, follow_dirlinks):
198-
for p in successor_select(starting_point, scandir, follow_symlinks):
199-
yield p
200-
except PermissionError:
201-
return
191+
successor_select = self.successor._select_from
192+
for starting_point in self._iterate_directories(parent_path, scandir, follow_dirlinks):
193+
for p in successor_select(starting_point, scandir, follow_symlinks):
194+
yield p
202195

203196

204197
class _DoubleRecursiveWildcardSelector(_RecursiveWildcardSelector):

Diff for: Lib/test/test_pathlib.py

+12-26
Original file line numberDiff line numberDiff line change
@@ -2032,33 +2032,19 @@ def test_glob_permissions(self):
20322032
P = self.cls
20332033
base = P(BASE) / 'permissions'
20342034
base.mkdir()
2035+
self.addCleanup(os_helper.rmtree, base)
20352036

2036-
file1 = base / "file1"
2037-
file1.touch()
2038-
file2 = base / "file2"
2039-
file2.touch()
2040-
2041-
subdir = base / "subdir"
2042-
2043-
file3 = base / "file3"
2044-
file3.symlink_to(subdir / "other")
2045-
2046-
# Patching is needed to avoid relying on the filesystem
2047-
# to return the order of the files as the error will not
2048-
# happen if the symlink is the last item.
2049-
real_scandir = os.scandir
2050-
def my_scandir(path):
2051-
with real_scandir(path) as scandir_it:
2052-
entries = list(scandir_it)
2053-
entries.sort(key=lambda entry: entry.name)
2054-
return contextlib.nullcontext(entries)
2055-
2056-
with mock.patch("os.scandir", my_scandir):
2057-
self.assertEqual(len(set(base.glob("*"))), 3)
2058-
subdir.mkdir()
2059-
self.assertEqual(len(set(base.glob("*"))), 4)
2060-
subdir.chmod(000)
2061-
self.assertEqual(len(set(base.glob("*"))), 4)
2037+
for i in range(100):
2038+
link = base / f"link{i}"
2039+
if i % 2:
2040+
link.symlink_to(P(BASE, "dirE", "nonexistent"))
2041+
else:
2042+
link.symlink_to(P(BASE, "dirC"))
2043+
2044+
self.assertEqual(len(set(base.glob("*"))), 100)
2045+
self.assertEqual(len(set(base.glob("*/"))), 50)
2046+
self.assertEqual(len(set(base.glob("*/fileC"))), 50)
2047+
self.assertEqual(len(set(base.glob("*/file*"))), 50)
20622048

20632049
@os_helper.skip_unless_symlink
20642050
def test_glob_long_symlink(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Remove ``_tkinter`` module code guarded by definition of the ``TK_AQUA`` macro
2+
which was only needed for Tk 8.4.7 or earlier and was never actually defined by
3+
any build system or documented for manual use.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fixed issue where :meth:`pathlib.Path.glob` returned incomplete results when
2+
it encountered a :exc:`PermissionError`. This method now suppresses all
3+
:exc:`OSError` exceptions, except those raised from calling
4+
:meth:`~pathlib.Path.is_dir` on the top-level path.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve performance of :func:`dataclasses.asdict` for the common case where
2+
*dict_factory* is ``dict``. Patch by David C Ellis.

Diff for: Modules/_tkinter.c

-14
Original file line numberDiff line numberDiff line change
@@ -3283,20 +3283,6 @@ PyInit__tkinter(void)
32833283
}
32843284
PyTclObject_Type = o;
32853285

3286-
#ifdef TK_AQUA
3287-
/* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems
3288-
* start waking up. Note that Tcl_FindExecutable will do this, this
3289-
* code must be above it! The original warning from
3290-
* tkMacOSXAppInit.c is copied below.
3291-
*
3292-
* NB - You have to swap in the Tk Notifier BEFORE you start up the
3293-
* Tcl interpreter for now. It probably should work to do this
3294-
* in the other order, but for now it doesn't seem to.
3295-
*
3296-
*/
3297-
Tk_MacOSXSetupTkNotifier();
3298-
#endif
3299-
33003286

33013287
/* This helps the dynamic loader; in Unicode aware Tcl versions
33023288
it also helps Tcl find its encodings. */

Diff for: Modules/tkappinit.c

-50
Original file line numberDiff line numberDiff line change
@@ -23,54 +23,9 @@ Tcl_AppInit(Tcl_Interp *interp)
2323
{
2424
const char *_tkinter_skip_tk_init;
2525

26-
#ifdef TK_AQUA
27-
#ifndef MAX_PATH_LEN
28-
#define MAX_PATH_LEN 1024
29-
#endif
30-
char tclLibPath[MAX_PATH_LEN], tkLibPath[MAX_PATH_LEN];
31-
Tcl_Obj* pathPtr;
32-
33-
/* pre- Tcl_Init code copied from tkMacOSXAppInit.c */
34-
Tk_MacOSXOpenBundleResources (interp, "com.tcltk.tcllibrary",
35-
tclLibPath, MAX_PATH_LEN, 0);
36-
37-
if (tclLibPath[0] != '\0') {
38-
Tcl_SetVar(interp, "tcl_library", tclLibPath, TCL_GLOBAL_ONLY);
39-
Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY);
40-
Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY);
41-
}
42-
43-
if (tclLibPath[0] != '\0') {
44-
Tcl_SetVar(interp, "tcl_library", tclLibPath, TCL_GLOBAL_ONLY);
45-
Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY);
46-
Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY);
47-
}
48-
#endif
4926
if (Tcl_Init (interp) == TCL_ERROR)
5027
return TCL_ERROR;
5128

52-
#ifdef TK_AQUA
53-
/* pre- Tk_Init code copied from tkMacOSXAppInit.c */
54-
Tk_MacOSXOpenBundleResources (interp, "com.tcltk.tklibrary",
55-
tkLibPath, MAX_PATH_LEN, 1);
56-
57-
if (tclLibPath[0] != '\0') {
58-
pathPtr = Tcl_NewStringObj(tclLibPath, -1);
59-
} else {
60-
Tcl_Obj *pathPtr = TclGetLibraryPath();
61-
}
62-
63-
if (tkLibPath[0] != '\0') {
64-
Tcl_Obj *objPtr;
65-
66-
Tcl_SetVar(interp, "tk_library", tkLibPath, TCL_GLOBAL_ONLY);
67-
objPtr = Tcl_NewStringObj(tkLibPath, -1);
68-
Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
69-
}
70-
71-
TclSetLibraryPath(pathPtr);
72-
#endif
73-
7429
#ifdef WITH_XXX
7530
/* Initialize modules that don't require Tk */
7631
#endif
@@ -88,11 +43,6 @@ Tcl_AppInit(Tcl_Interp *interp)
8843

8944
Tk_MainWindow(interp);
9045

91-
#ifdef TK_AQUA
92-
TkMacOSXInitAppleEvents(interp);
93-
TkMacOSXInitMenus(interp);
94-
#endif
95-
9646
#ifdef WITH_PIL /* 0.2b5 and later -- not yet released as of May 14 */
9747
{
9848
extern void TkImaging_Init(Tcl_Interp *);

Diff for: Objects/genobject.c

-3
Original file line numberDiff line numberDiff line change
@@ -1406,9 +1406,6 @@ typedef struct _PyAsyncGenWrappedValue {
14061406
#define _PyAsyncGenWrappedValue_CheckExact(o) \
14071407
Py_IS_TYPE(o, &_PyAsyncGenWrappedValue_Type)
14081408

1409-
#define PyAsyncGenASend_CheckExact(o) \
1410-
Py_IS_TYPE(o, &_PyAsyncGenASend_Type)
1411-
14121409

14131410
static int
14141411
async_gen_traverse(PyAsyncGenObject *gen, visitproc visit, void *arg)

Diff for: Python/specialize.c

+45-41
Original file line numberDiff line numberDiff line change
@@ -436,27 +436,28 @@ _PyCode_Quicken(PyCodeObject *code)
436436
#define SPEC_FAIL_COMPARE_OP_FLOAT_LONG 21
437437
#define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 22
438438

439-
/* FOR_ITER */
440-
#define SPEC_FAIL_FOR_ITER_GENERATOR 10
441-
#define SPEC_FAIL_FOR_ITER_COROUTINE 11
442-
#define SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR 12
443-
#define SPEC_FAIL_FOR_ITER_LIST 13
444-
#define SPEC_FAIL_FOR_ITER_TUPLE 14
445-
#define SPEC_FAIL_FOR_ITER_SET 15
446-
#define SPEC_FAIL_FOR_ITER_STRING 16
447-
#define SPEC_FAIL_FOR_ITER_BYTES 17
448-
#define SPEC_FAIL_FOR_ITER_RANGE 18
449-
#define SPEC_FAIL_FOR_ITER_ITERTOOLS 19
450-
#define SPEC_FAIL_FOR_ITER_DICT_KEYS 20
451-
#define SPEC_FAIL_FOR_ITER_DICT_ITEMS 21
452-
#define SPEC_FAIL_FOR_ITER_DICT_VALUES 22
453-
#define SPEC_FAIL_FOR_ITER_ENUMERATE 23
454-
#define SPEC_FAIL_FOR_ITER_MAP 24
455-
#define SPEC_FAIL_FOR_ITER_ZIP 25
456-
#define SPEC_FAIL_FOR_ITER_SEQ_ITER 26
457-
#define SPEC_FAIL_FOR_ITER_REVERSED_LIST 27
458-
#define SPEC_FAIL_FOR_ITER_CALLABLE 28
459-
#define SPEC_FAIL_FOR_ITER_ASCII_STRING 29
439+
/* FOR_ITER and SEND */
440+
#define SPEC_FAIL_ITER_GENERATOR 10
441+
#define SPEC_FAIL_ITER_COROUTINE 11
442+
#define SPEC_FAIL_ITER_ASYNC_GENERATOR 12
443+
#define SPEC_FAIL_ITER_LIST 13
444+
#define SPEC_FAIL_ITER_TUPLE 14
445+
#define SPEC_FAIL_ITER_SET 15
446+
#define SPEC_FAIL_ITER_STRING 16
447+
#define SPEC_FAIL_ITER_BYTES 17
448+
#define SPEC_FAIL_ITER_RANGE 18
449+
#define SPEC_FAIL_ITER_ITERTOOLS 19
450+
#define SPEC_FAIL_ITER_DICT_KEYS 20
451+
#define SPEC_FAIL_ITER_DICT_ITEMS 21
452+
#define SPEC_FAIL_ITER_DICT_VALUES 22
453+
#define SPEC_FAIL_ITER_ENUMERATE 23
454+
#define SPEC_FAIL_ITER_MAP 24
455+
#define SPEC_FAIL_ITER_ZIP 25
456+
#define SPEC_FAIL_ITER_SEQ_ITER 26
457+
#define SPEC_FAIL_ITER_REVERSED_LIST 27
458+
#define SPEC_FAIL_ITER_CALLABLE 28
459+
#define SPEC_FAIL_ITER_ASCII_STRING 29
460+
#define SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND 30
460461

461462
// UNPACK_SEQUENCE
462463

@@ -2122,66 +2123,69 @@ int
21222123
_PySpecialization_ClassifyIterator(PyObject *iter)
21232124
{
21242125
if (PyGen_CheckExact(iter)) {
2125-
return SPEC_FAIL_FOR_ITER_GENERATOR;
2126+
return SPEC_FAIL_ITER_GENERATOR;
21262127
}
21272128
if (PyCoro_CheckExact(iter)) {
2128-
return SPEC_FAIL_FOR_ITER_COROUTINE;
2129+
return SPEC_FAIL_ITER_COROUTINE;
21292130
}
21302131
if (PyAsyncGen_CheckExact(iter)) {
2131-
return SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR;
2132+
return SPEC_FAIL_ITER_ASYNC_GENERATOR;
2133+
}
2134+
if (PyAsyncGenASend_CheckExact(iter)) {
2135+
return SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND;
21322136
}
21332137
PyTypeObject *t = Py_TYPE(iter);
21342138
if (t == &PyListIter_Type) {
2135-
return SPEC_FAIL_FOR_ITER_LIST;
2139+
return SPEC_FAIL_ITER_LIST;
21362140
}
21372141
if (t == &PyTupleIter_Type) {
2138-
return SPEC_FAIL_FOR_ITER_TUPLE;
2142+
return SPEC_FAIL_ITER_TUPLE;
21392143
}
21402144
if (t == &PyDictIterKey_Type) {
2141-
return SPEC_FAIL_FOR_ITER_DICT_KEYS;
2145+
return SPEC_FAIL_ITER_DICT_KEYS;
21422146
}
21432147
if (t == &PyDictIterValue_Type) {
2144-
return SPEC_FAIL_FOR_ITER_DICT_VALUES;
2148+
return SPEC_FAIL_ITER_DICT_VALUES;
21452149
}
21462150
if (t == &PyDictIterItem_Type) {
2147-
return SPEC_FAIL_FOR_ITER_DICT_ITEMS;
2151+
return SPEC_FAIL_ITER_DICT_ITEMS;
21482152
}
21492153
if (t == &PySetIter_Type) {
2150-
return SPEC_FAIL_FOR_ITER_SET;
2154+
return SPEC_FAIL_ITER_SET;
21512155
}
21522156
if (t == &PyUnicodeIter_Type) {
2153-
return SPEC_FAIL_FOR_ITER_STRING;
2157+
return SPEC_FAIL_ITER_STRING;
21542158
}
21552159
if (t == &PyBytesIter_Type) {
2156-
return SPEC_FAIL_FOR_ITER_BYTES;
2160+
return SPEC_FAIL_ITER_BYTES;
21572161
}
21582162
if (t == &PyRangeIter_Type) {
2159-
return SPEC_FAIL_FOR_ITER_RANGE;
2163+
return SPEC_FAIL_ITER_RANGE;
21602164
}
21612165
if (t == &PyEnum_Type) {
2162-
return SPEC_FAIL_FOR_ITER_ENUMERATE;
2166+
return SPEC_FAIL_ITER_ENUMERATE;
21632167
}
21642168
if (t == &PyMap_Type) {
2165-
return SPEC_FAIL_FOR_ITER_MAP;
2169+
return SPEC_FAIL_ITER_MAP;
21662170
}
21672171
if (t == &PyZip_Type) {
2168-
return SPEC_FAIL_FOR_ITER_ZIP;
2172+
return SPEC_FAIL_ITER_ZIP;
21692173
}
21702174
if (t == &PySeqIter_Type) {
2171-
return SPEC_FAIL_FOR_ITER_SEQ_ITER;
2175+
return SPEC_FAIL_ITER_SEQ_ITER;
21722176
}
21732177
if (t == &PyListRevIter_Type) {
2174-
return SPEC_FAIL_FOR_ITER_REVERSED_LIST;
2178+
return SPEC_FAIL_ITER_REVERSED_LIST;
21752179
}
21762180
if (t == &_PyUnicodeASCIIIter_Type) {
2177-
return SPEC_FAIL_FOR_ITER_ASCII_STRING;
2181+
return SPEC_FAIL_ITER_ASCII_STRING;
21782182
}
21792183
const char *name = t->tp_name;
21802184
if (strncmp(name, "itertools", 9) == 0) {
2181-
return SPEC_FAIL_FOR_ITER_ITERTOOLS;
2185+
return SPEC_FAIL_ITER_ITERTOOLS;
21822186
}
21832187
if (strncmp(name, "callable_iterator", 17) == 0) {
2184-
return SPEC_FAIL_FOR_ITER_CALLABLE;
2188+
return SPEC_FAIL_ITER_CALLABLE;
21852189
}
21862190
return SPEC_FAIL_OTHER;
21872191
}

0 commit comments

Comments
 (0)