A :class:`~io.TextIOWrapper` with custom ``name`` and ``mode`` that does not close its underlying buffer. When ``CliRunner`` runs in ``fd`` mode, ``_original_fd`` is patched to point at the saved (pre-redirection) ``fd``, so C-level consumers that call :meth:`fileno` (like ``faultha
| 154 | |
| 155 | |
| 156 | class _NamedTextIOWrapper(io.TextIOWrapper): |
| 157 | """A :class:`~io.TextIOWrapper` with custom ``name`` and ``mode`` |
| 158 | that does not close its underlying buffer. |
| 159 | |
| 160 | When ``CliRunner`` runs in ``fd`` mode, ``_original_fd`` is patched to |
| 161 | point at the saved (pre-redirection) ``fd``, so C-level consumers that call |
| 162 | :meth:`fileno` (like ``faulthandler`` or ``subprocess``) keep working. In |
| 163 | the default ``sys`` mode ``_original_fd`` stays at ``-1`` and |
| 164 | :meth:`fileno` raises :exc:`io.UnsupportedOperation`, matching the |
| 165 | pre-``8.3.3`` behavior. |
| 166 | """ |
| 167 | |
| 168 | _name: str |
| 169 | _mode: str |
| 170 | _original_fd: int |
| 171 | |
| 172 | def __init__( |
| 173 | self, |
| 174 | buffer: t.BinaryIO, |
| 175 | name: str, |
| 176 | mode: str, |
| 177 | **kwargs: t.Any, |
| 178 | ) -> None: |
| 179 | super().__init__(buffer, **kwargs) |
| 180 | self._name = name |
| 181 | self._mode = mode |
| 182 | self._original_fd = -1 |
| 183 | |
| 184 | def close(self) -> None: |
| 185 | """The buffer this object contains belongs to some other object, |
| 186 | so prevent the default ``__del__`` implementation from closing |
| 187 | that buffer. |
| 188 | |
| 189 | .. versionadded:: 8.3.2 |
| 190 | """ |
| 191 | |
| 192 | def fileno(self) -> int: |
| 193 | """Return the file descriptor of the saved original stream when |
| 194 | ``CliRunner`` runs in ``fd`` mode. Otherwise delegate to |
| 195 | :class:`~io.TextIOWrapper`, which raises |
| 196 | :exc:`io.UnsupportedOperation` for a ``BytesIO``-backed buffer. |
| 197 | """ |
| 198 | if self._original_fd >= 0: |
| 199 | return self._original_fd |
| 200 | return super().fileno() |
| 201 | |
| 202 | @property |
| 203 | def name(self) -> str: |
| 204 | return self._name |
| 205 | |
| 206 | @property |
| 207 | def mode(self) -> str: |
| 208 | return self._mode |
| 209 | |
| 210 | |
| 211 | def make_input_stream( |
no outgoing calls