@@ -11937,8 +11937,14 @@ typedef struct {
1193711937
1193811938#ifdef MS_WINDOWS
1193911939
11940+ static int
11941+ ScandirIterator_is_closed (ScandirIterator * iterator )
11942+ {
11943+ return iterator -> handle == INVALID_HANDLE_VALUE ;
11944+ }
11945+
1194011946static void
11941- ScandirIterator_close (ScandirIterator * iterator )
11947+ ScandirIterator_closedir (ScandirIterator * iterator )
1194211948{
1194311949 if (iterator -> handle == INVALID_HANDLE_VALUE )
1194411950 return ;
@@ -11956,7 +11962,7 @@ ScandirIterator_iternext(ScandirIterator *iterator)
1195611962 BOOL success ;
1195711963 PyObject * entry ;
1195811964
11959- /* Happens if the iterator is iterated twice */
11965+ /* Happens if the iterator is iterated twice, or closed explicitly */
1196011966 if (iterator -> handle == INVALID_HANDLE_VALUE )
1196111967 return NULL ;
1196211968
@@ -11987,14 +11993,20 @@ ScandirIterator_iternext(ScandirIterator *iterator)
1198711993 }
1198811994
1198911995 /* Error or no more files */
11990- ScandirIterator_close (iterator );
11996+ ScandirIterator_closedir (iterator );
1199111997 return NULL ;
1199211998}
1199311999
1199412000#else /* POSIX */
1199512001
12002+ static int
12003+ ScandirIterator_is_closed (ScandirIterator * iterator )
12004+ {
12005+ return !iterator -> dirp ;
12006+ }
12007+
1199612008static void
11997- ScandirIterator_close (ScandirIterator * iterator )
12009+ ScandirIterator_closedir (ScandirIterator * iterator )
1199812010{
1199912011 if (!iterator -> dirp )
1200012012 return ;
@@ -12014,7 +12026,7 @@ ScandirIterator_iternext(ScandirIterator *iterator)
1201412026 int is_dot ;
1201512027 PyObject * entry ;
1201612028
12017- /* Happens if the iterator is iterated twice */
12029+ /* Happens if the iterator is iterated twice, or closed explicitly */
1201812030 if (!iterator -> dirp )
1201912031 return NULL ;
1202012032
@@ -12051,21 +12063,67 @@ ScandirIterator_iternext(ScandirIterator *iterator)
1205112063 }
1205212064
1205312065 /* Error or no more files */
12054- ScandirIterator_close (iterator );
12066+ ScandirIterator_closedir (iterator );
1205512067 return NULL ;
1205612068}
1205712069
1205812070#endif
1205912071
12072+ static PyObject *
12073+ ScandirIterator_close (ScandirIterator * self , PyObject * args )
12074+ {
12075+ ScandirIterator_closedir (self );
12076+ Py_RETURN_NONE ;
12077+ }
12078+
12079+ static PyObject *
12080+ ScandirIterator_enter (PyObject * self , PyObject * args )
12081+ {
12082+ Py_INCREF (self );
12083+ return self ;
12084+ }
12085+
12086+ static PyObject *
12087+ ScandirIterator_exit (ScandirIterator * self , PyObject * args )
12088+ {
12089+ ScandirIterator_closedir (self );
12090+ Py_RETURN_NONE ;
12091+ }
12092+
1206012093static void
1206112094ScandirIterator_dealloc (ScandirIterator * iterator )
1206212095{
12063- ScandirIterator_close (iterator );
12096+ if (!ScandirIterator_is_closed (iterator )) {
12097+ PyObject * exc , * val , * tb ;
12098+ Py_ssize_t old_refcount = Py_REFCNT (iterator );
12099+ /* Py_INCREF/Py_DECREF cannot be used, because the refcount is
12100+ * likely zero, Py_DECREF would call again the destructor.
12101+ */
12102+ ++ Py_REFCNT (iterator );
12103+ PyErr_Fetch (& exc , & val , & tb );
12104+ if (PyErr_WarnFormat (PyExc_ResourceWarning , 1 ,
12105+ "unclosed scandir iterator %R" , iterator )) {
12106+ /* Spurious errors can appear at shutdown */
12107+ if (PyErr_ExceptionMatches (PyExc_Warning ))
12108+ PyErr_WriteUnraisable ((PyObject * ) iterator );
12109+ }
12110+ PyErr_Restore (exc , val , tb );
12111+ Py_REFCNT (iterator ) = old_refcount ;
12112+
12113+ ScandirIterator_closedir (iterator );
12114+ }
1206412115 Py_XDECREF (iterator -> path .object );
1206512116 path_cleanup (& iterator -> path );
1206612117 Py_TYPE (iterator )-> tp_free ((PyObject * )iterator );
1206712118}
1206812119
12120+ static PyMethodDef ScandirIterator_methods [] = {
12121+ {"__enter__" , (PyCFunction )ScandirIterator_enter , METH_NOARGS },
12122+ {"__exit__" , (PyCFunction )ScandirIterator_exit , METH_VARARGS },
12123+ {"close" , (PyCFunction )ScandirIterator_close , METH_NOARGS },
12124+ {NULL }
12125+ };
12126+
1206912127static PyTypeObject ScandirIteratorType = {
1207012128 PyVarObject_HEAD_INIT (NULL , 0 )
1207112129 MODNAME ".ScandirIterator" , /* tp_name */
@@ -12095,6 +12153,7 @@ static PyTypeObject ScandirIteratorType = {
1209512153 0 , /* tp_weaklistoffset */
1209612154 PyObject_SelfIter , /* tp_iter */
1209712155 (iternextfunc )ScandirIterator_iternext , /* tp_iternext */
12156+ ScandirIterator_methods , /* tp_methods */
1209812157};
1209912158
1210012159static PyObject *
0 commit comments