{"id":"d6573254d6dfa459","repo":"pytest-dev/pytest","slug":"redirected-stdin-is-pseudofile-has-no-fileno","errorCode":null,"errorMessage":"redirected stdin is pseudofile, has no fileno()","messagePattern":"redirected stdin is pseudofile, has no fileno\\(\\)","errorType":"exception","errorClass":"UnsupportedOperation","httpStatus":null,"severity":"error","filePath":"src/_pytest/capture.py","lineNumber":247,"sourceCode":"        raise OSError(\n            \"pytest: reading from stdin while output is captured!  Consider using `-s`.\"\n        )\n\n    readline = read\n\n    def __next__(self) -> str:\n        return self.readline()\n\n    def readlines(self, hint: int | None = -1) -> list[str]:\n        raise OSError(\n            \"pytest: reading from stdin while output is captured!  Consider using `-s`.\"\n        )\n\n    def __iter__(self) -> Iterator[str]:\n        return self\n\n    def fileno(self) -> int:\n        raise UnsupportedOperation(\"redirected stdin is pseudofile, has no fileno()\")\n\n    def flush(self) -> None:\n        raise UnsupportedOperation(\"redirected stdin is pseudofile, has no flush()\")\n\n    def isatty(self) -> bool:\n        return False\n\n    def close(self) -> None:\n        pass\n\n    def readable(self) -> bool:\n        return False\n\n    def seek(self, offset: int, whence: int = 0) -> int:\n        raise UnsupportedOperation(\"redirected stdin is pseudofile, has no seek(int)\")\n\n    def seekable(self) -> bool:\n        return False","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/capture.py#L229-L265","documentation":"DontReadFromInput.fileno() raises UnsupportedOperation because the captured stdin is a pseudo-file backed by an in-memory buffer, not a real OS file descriptor. Code that calls fileno() (e.g. to do raw I/O or pass the fd to subprocess/select) cannot work on it.","triggerScenarios":"In a test under default capture, code calls sys.stdin.fileno() — common in libraries that use select.select([sys.stdin], ...) or os.read(sys.stdin.fileno(), n).","commonSituations":"Interactive prompt libraries (e.g. readline-based, getpass) that probe fileno(); libraries that integrate with select/poll on stdin; code that hands stdin's fd to a subprocess.","solutions":["Run pytest with -s so sys.stdin is the real terminal stream.","Refactor the code under test to accept a file object or fd explicitly rather than reaching for sys.stdin.fileno().","Monkeypatch sys.stdin with an object that exposes a real fileno (e.g. an open temp file)."],"exampleFix":"// before\n# code under test: fd = sys.stdin.fileno()\n// after\n$ pytest -s","handlingStrategy":"type-guard","validationCode":"import sys\n\ndef safe_fileno(stream):\n    if type(stream).__name__ == 'DontReadFromInput':\n        raise UnsupportedOperation('stdin is a pseudofile under pytest capture')\n    return stream.fileno()","typeGuard":"def has_real_fileno(stream) -> bool:\n    return type(stream).__name__ != 'DontReadFromInput' and hasattr(stream, 'fileno')","tryCatchPattern":"from io import UnsupportedOperation\ntry:\n    fd = sys.stdin.fileno()\nexcept (OSError, UnsupportedOperation, ValueError):\n    fd = None  # fall back to higher-level read APIs","preventionTips":["Do not call fileno() on streams you do not own; accept an explicit fd or file object from the caller.","Guard select/select usage on stdin with a fileno() try/except."],"tags":["pytest","capture","stdin","io"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}