{"record":{"id":"442faef37eb9e7d2","repo":"pytest-dev/pytest","slug":"redirected-stdin-is-pseudofile-has-no-tell","errorCode":null,"errorMessage":"redirected stdin is pseudofile, has no tell()","messagePattern":"redirected stdin is pseudofile, has no tell\\(\\)","errorType":"exception","errorClass":"UnsupportedOperation","httpStatus":null,"severity":"error","filePath":"src/_pytest/capture.py","lineNumber":268,"sourceCode":"        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\n\n    def tell(self) -> int:\n        raise UnsupportedOperation(\"redirected stdin is pseudofile, has no tell()\")\n\n    def truncate(self, size: int | None = None) -> int:\n        raise UnsupportedOperation(\"cannot truncate stdin\")\n\n    def write(self, data: str) -> int:\n        raise UnsupportedOperation(\"cannot write to stdin\")\n\n    def writelines(self, lines: Iterable[str]) -> None:\n        raise UnsupportedOperation(\"Cannot write to stdin\")\n\n    def writable(self) -> bool:\n        return False\n\n    def __enter__(self) -> Self:\n        return self\n\n    def __exit__(\n        self,","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/capture.py#L250-L286","documentation":"Raised by DontReadFromInput.tell() (src/_pytest/capture.py:267). tell() is unsupported because the redirected stdin pseudo-file keeps no position cursor; pytest raises UnsupportedOperation to surface the misuse rather than return a fabricated position. seekable()/writable()/readable() all return False to advertise this.","triggerScenarios":"Calling sys.stdin.tell() in a test while the default capture is active. tell() at capture.py:267 always raises; there is no probe like seekable() for tell, so the call must be guarded by the caller.","commonSituations":"Logging libraries, terminal UIs (rich, tqdm), and test harnesses that record the current stream position before/after reads. Triggered when such code runs against sys.stdin under default pytest capture.","solutions":["Disable capture with -s or --capture=no for that test/run","Wrap the tell() call in try/except (OSError, ValueError) - UnsupportedOperation subclasses both","Inject an io.StringIO into sys.stdin before the call so tell() is real","Use the capsys/capfd fixture's stop()/resume() around the offending code"],"exampleFix":"// before\npos = sys.stdin.tell()\n// after\ntry:\n    pos = sys.stdin.tell()\nexcept OSError:\n    pos = -1","handlingStrategy":"try-catch","validationCode":"import sys\n# No probe method for tell(); must rely on seekable() as a proxy\nif not sys.stdin.seekable():\n    pass","typeGuard":"def safe_tell(stream) -> int | None:\n    try:\n        return stream.tell()\n    except OSError:\n        return None","tryCatchPattern":"try:\n    pos = sys.stdin.tell()\nexcept OSError:\n    pos = None","preventionTips":["Treat tell() as best-effort on streams you did not construct","Disable pytest capture when testing code that relies on stdin position tracking","Prefer io.StringIO or io.BytesIO in test fixtures for stream-position-sensitive code"],"tags":["capture","stdin","io","unsupported-operation"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}