Repository: Rapptz/discord.py
File: discord/player.py (Python)

Code before:
            self._pipe_writer_thread = threading.Thread(target=self._pipe_writer, args=(source,), daemon=True, name=n)
            self._pipe_writer_thread.start()

        if piping_stderr:
            n = f'popen-stderr-reader:pid-{self._process.pid}'
            self._stderr = self._process.stderr
            self._pipe_reader_thread = threading.Thread(target=self._pipe_reader, args=(stderr,), daemon=True, name=n)
            self._pipe_reader_thread.start()

    def _spawn_process(self, args: Any, **subprocess_kwargs: Any) -> subprocess.Popen:
        _log.debug('Spawning ffmpeg process with command: %s', args)
        process = None
        try:
            process = subprocess.Popen(args, creationflags=CREATE_NO_WINDOW, **subprocess_kwargs)
        except FileNotFoundError:
            executable = args.partition(' ')[0] if isinstance(args, str) else args[0]
            raise ClientException(executable + ' was not found.') from None
        except subprocess.SubprocessError as exc:
            raise ClientException(f'Popen failed: {exc.__class__.__name__}: {exc}') from exc
        else:
            return process

    def _check_process_returncode(self) -> None:
        """Set _current_error if FFmpeg exited with a non-zero code."""
        proc = getattr(self, '_process', None)
        if proc is None or not hasattr(proc, 'poll') or type(proc).__name__ == '_MissingSentinel':
            return

        ret = proc.poll()
        if ret is None:
            return  # still running

        if getattr(self, '_stopped', False):
            return  # intentionally stopped

        if ret != 0 and self._current_error is None:
            # Only set error once, on first detection
            # read stderr if available
            stderr_text = None
            if self._stderr:
                try:
                    stderr_text = self._stderr.read(8192).decode(errors='ignore')
                except Exception:
                    stderr_text = '<failed to read stderr>'

            stderr_info = stderr_text if stderr_text else '<no stderr>'
            self._current_error = FFmpegError(f'FFmpeg exited with code {ret}. Stderr: {stderr_info}')

    def _kill_process(self) -> None:
        # check if FFmpeg process failed
        self._check_process_returncode()

Review comment (suggestion):
The rest of the library uses `value is MISSING` instead of `type(value).__name__ == '_MissingSentinel'`. The attribute is also explicitly assigned MISSING prior to calling subprocess.Popen for the case where exceptions occur, so getattr should always find a value. `.poll()` should always exist if it's a subprocess.Popen object.
```diff
-         proc = getattr(self, '_process', None)
-         if proc is None or not hasattr(proc, 'poll') or type(proc).__name__ == '_MissingSentinel':
+         if self._process is MISSING:
```

Code after:
            self._stdin = self._process.stdin
            self._pipe_writer_thread = threading.Thread(target=self._pipe_writer, args=(source,), daemon=True, name=n)
            self._pipe_writer_thread.start()

        if piping_stderr:
            n = f'popen-stderr-reader:pid-{self._process.pid}'
            self._stderr = self._process.stderr
            self._pipe_reader_thread = threading.Thread(target=self._pipe_reader, args=(stderr,), daemon=True, name=n)
            self._pipe_reader_thread.start()

    def _spawn_process(self, args: Any, **subprocess_kwargs: Any) -> subprocess.Popen:
        _log.debug('Spawning ffmpeg process with command: %s', args)
        process = None
        try:
            process = subprocess.Popen(args, creationflags=CREATE_NO_WINDOW, **subprocess_kwargs)
        except FileNotFoundError:
            executable = args.partition(' ')[0] if isinstance(args, str) else args[0]
            raise ClientException(executable + ' was not found.') from None
        except subprocess.SubprocessError as exc:
            raise ClientException(f'Popen failed: {exc.__class__.__name__}: {exc}') from exc
        else:
            return process

    def _check_process_returncode(self) -> None:
        """Set _current_error if FFmpeg exited with a non-zero code."""
        if self._process is MISSING:
            return

        ret = self._process.poll()
        if ret is None:
            return  # still running

        if self._stopped:
            return  # intentionally stopped

        if ret != 0 and self._current_error is None:
            # Only set error once, on first detection
            # read stderr if available
            stderr_text = None
            if self._stderr:
                try:
                    stderr_text = self._stderr.read(8192).decode(errors='ignore')
                except Exception:
                    stderr_text = '<failed to read stderr>'

            stderr_info = stderr_text if stderr_text else '<no stderr>'
            self._current_error = FFmpegProcessError(f'FFmpeg exited with code {ret}. Stderr: {stderr_info}')

    def _kill_process(self) -> None:
        # check if FFmpeg process failed
        self._check_process_returncode()