AttributeError: la instancia de StringIO no tiene atributo ‘fileno’

def captureOutput(self, func, *args, **kwargs): pass sys.stdout.flush() sys.stderr.flush() (outfd, fn) = tempfile.mkstemp() fout = os.fdopen(outfd, 'r') os.unlink(fn) (errfd, fn) = tempfile.mkstemp() ferr = os.fdopen(errfd, 'r') os.unlink(fn) try: oldstdout = os.dup(sys.stdout.fileno()) oldstderr = os.dup(sys.stderr.fileno()) os.dup2(outfd, sys.stdout.fileno()) os.dup2(errfd, sys.stderr.fileno()) try: ret = func(*args, **kwargs) finally: sys.stderr.flush() sys.stdout.flush() os.dup2(oldstdout, sys.stdout.fileno()) os.close(oldstdout) os.dup2(oldstderr, sys.stderr.fileno()) os.close(oldstderr) os.lseek(outfd, 0, 0) out = fout.read() os.lseek(errfd, 0, 0) err = ferr.read() finally: fout.close() ferr.close() return ret, out, err 

Al ejecutar este código, me sale un error:

 AttributeError: la instancia de StringIO no tiene atributo 'fileno'

¿Por qué recibo este error y cómo puedo corregirlo?

¿Está utilizando el intérprete estándar de python? Este error puede aparecer cuando usa un intérprete que reemplaza stdout / stderr, como IDLE (aunque IDLE en sí le daría un error diferente). También puede ser causado por una biblioteca que reemplaza a stdout / stderr.

A veces, puede restablecer su stdout el stdout predeterminado escribiendo sys.stdout = sys.__stdout__ , pero no cuente con que funcione siempre. No funciona en Pythonwin por ejemplo.

De todos modos, parece que lo que estás tratando de hacer con tu código es redirigir tú mismo / stderut. Si ese es el caso, debes seguir adelante y hacerlo. Creo que esto debería funcionar, si tiene descriptores de archivo outfd y errfd :

 sys.stdout = os.fdopen(outfd, 'w') sys.stderr = os.fdopen(errfd, 'w') 

Editar:

Ahora que puedo ver su código completo, no usaría ningún archivo temporal.

 def captureOutput(self, func, *args, **kwargs): import cStringIO # You can also use StringIO instead sys.stderr.flush() sys.stdout.flush() olderr, oldout = sys.stderr, sys.stdout try: sys.stderr = cStringIO.StringIO() sys.stdout = cStringIO.StringIO() try: ret = func(*args, **kwargs) finally: stderr.seek(0) stdout.seek(0) err = stderr.read() out = stdout.read() finally: sys.stderr = olderr sys.stdout = oldout return ret, out, err 

El método fileno() no se implementa en StringIO, ya que no es un archivo real (por lo que no tiene un descriptor de archivo asociado). De la fuente:

 - fileno() is left unimplemented so that code which uses it triggers an exception early. 

Es posible que alguien haya reemplazado sys.stdout con una instancia de StringIO para capturar la salida.

Por ejemplo, cuando ejecuto su código de esta manera, obtengo la misma excepción:

 from StringIO import StringIO sys.stdout = StringIO() captureOutput(testfunc) 

Error:

  oldstdout = os.dup(sys.stdout.fileno()) AttributeError: StringIO instance has no attribute 'fileno' 

Podría ser mejor rastrear su código de un extremo a otro, buscando puntos donde se sobrescriba sys.stdout . Aquí hay un enlace a otra respuesta que di , que muestra cómo ejecutar su código con rastreo activo:

 ares% python -m trace -c -t -C ./coverage test_sio.py | grep sys.stdout test_sio.py(47): sys.stdout = StringIO() 

Mi conjetura sería en otro lugar en el código, sys.stdout o sys.stderr fue reasignado para ser una instancia de StringIO. ¿En qué entorno (como dentro de un marco web, desde la línea de comandos) se ejecuta este código? Eso podría dar a alguien familiarizado con ese entorno una pista en cuanto a la respuesta correcta.

La respuesta corta es que se encontró con un error en la biblioteca estándar. StringIO no cumple el contrato de su clase base IOBase. Alguna clase escribió a la interfaz de clase IOBase, que luego falla.

Más específicamente, Subprocess.run () o alguna otra función utilizó la función IOBase fileno. La subclase StringIO lanza esta excepción porque no es una subclase verdadera. En algún lugar, uno de los muchos usuarios de IOBase falla. Documentar StringIO no ayuda con este problema.

Puede codificar a su alrededor, tal vez. O tal vez no. Todo tipo de funciones como contextlib.redirect_stdout () fallarán.