@@ -212,9 +212,9 @@ static int
212212fileio_init (PyObject * oself , PyObject * args , PyObject * kwds )
213213{
214214 fileio * self = (fileio * ) oself ;
215- static char * kwlist [] = {"file" , "mode" , "closefd" , NULL };
215+ static char * kwlist [] = {"file" , "mode" , "closefd" , "opener" , NULL };
216216 const char * name = NULL ;
217- PyObject * nameobj , * stringobj = NULL ;
217+ PyObject * nameobj , * stringobj = NULL , * opener = Py_None ;
218218 char * mode = "r" ;
219219 char * s ;
220220#ifdef MS_WINDOWS
@@ -233,8 +233,9 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
233233 return -1 ;
234234 }
235235
236- if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|si:fileio" ,
237- kwlist , & nameobj , & mode , & closefd ))
236+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|siO:fileio" ,
237+ kwlist , & nameobj , & mode , & closefd ,
238+ & opener ))
238239 return -1 ;
239240
240241 if (PyFloat_Check (nameobj )) {
@@ -363,15 +364,35 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
363364 goto error ;
364365 }
365366
366- Py_BEGIN_ALLOW_THREADS
367367 errno = 0 ;
368+ if (opener == Py_None ) {
369+ Py_BEGIN_ALLOW_THREADS
368370#ifdef MS_WINDOWS
369- if (widename != NULL )
370- self -> fd = _wopen (widename , flags , 0666 );
371- else
371+ if (widename != NULL )
372+ self -> fd = _wopen (widename , flags , 0666 );
373+ else
372374#endif
373- self -> fd = open (name , flags , 0666 );
374- Py_END_ALLOW_THREADS
375+ self -> fd = open (name , flags , 0666 );
376+ Py_END_ALLOW_THREADS
377+ } else {
378+ PyObject * fdobj = PyObject_CallFunction (
379+ opener , "Oi" , nameobj , flags );
380+ if (fdobj == NULL )
381+ goto error ;
382+ if (!PyLong_Check (fdobj )) {
383+ Py_DECREF (fdobj );
384+ PyErr_SetString (PyExc_TypeError ,
385+ "expected integer from opener" );
386+ goto error ;
387+ }
388+
389+ self -> fd = PyLong_AsLong (fdobj );
390+ Py_DECREF (fdobj );
391+ if (self -> fd == -1 ) {
392+ goto error ;
393+ }
394+ }
395+
375396 if (self -> fd < 0 ) {
376397#ifdef MS_WINDOWS
377398 if (widename != NULL )
@@ -1017,13 +1038,17 @@ fileio_getstate(fileio *self)
10171038
10181039
10191040PyDoc_STRVAR (fileio_doc ,
1020- "file(name: str[, mode: str]) -> file IO object\n"
1041+ "file(name: str[, mode: str][, opener: None] ) -> file IO object\n"
10211042"\n"
10221043"Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"
10231044"writing or appending. The file will be created if it doesn't exist\n"
10241045"when opened for writing or appending; it will be truncated when\n"
10251046"opened for writing. Add a '+' to the mode to allow simultaneous\n"
1026- "reading and writing." );
1047+ "reading and writing. A custom opener can be used by passing a\n"
1048+ "callable as *opener*. The underlying file descriptor for the file\n"
1049+ "object is then obtained by calling opener with (*name*, *flags*).\n"
1050+ "*opener* must return an open file descriptor (passing os.open as\n"
1051+ "*opener* results in functionality similar to passing None)." );
10271052
10281053PyDoc_STRVAR (read_doc ,
10291054"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
0 commit comments