Skip to content

cli: add devnull fallback for missing stdout fd #6197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 23, 2024

Conversation

bastimeyer
Copy link
Member

Follow-up of #6142

This fixes the case where sys.stdout is None, when the Python process doesn't have the stdout file descriptor (fd1). This can be forced in BASH for example, by appending >&-.

import pathlib,os,sys
pid = str(os.getpid())
fd1 = pathlib.Path("/proc", pid, "fd", "1")
sys.stderr.write(f"{pid=}\n{sys.stdout is None=}\n{fd1.readlink() if fd1.exists() else None=}\n")
$ python <<< "${CODE}"
pid='318408'
sys.stdout is None=False
fd1.readlink() if fd1.exists() else None=PosixPath('/dev/pts/2')
$ python <<< "${CODE}" >&-
pid='318428'
sys.stdout is None=True
fd1.readlink() if fd1.exists() else None=None

Currently on master, this results in an AttributeError, as the streamlink_cli.compat module assigns its stdout attribute to sys.stdout.buffer, the binary output stream used for writing stream content to stdout (e.g. --stdout).

So when fd1 is missing and sys.stdout is None, we need a fallback stream. Simply use a devnull output stream in this case (and close it on exit).

When stdout is missing, the logging stream and console output stream will automatically be stderr.


master

$ streamlink >&-
Traceback (most recent call last):
  File "/home/basti/venv/streamlink-312/bin/streamlink", line 5, in <module>
    from streamlink_cli.main import main
  File "/home/basti/repos/streamlink/src/streamlink_cli/main.py", line 25, in <module>
    from streamlink_cli.argparser import ArgumentParser, build_parser, setup_session_options
  File "/home/basti/repos/streamlink/src/streamlink_cli/argparser.py", line 13, in <module>
    from streamlink_cli.constants import STREAM_PASSTHROUGH
  File "/home/basti/repos/streamlink/src/streamlink_cli/constants.py", line 7, in <module>
    from streamlink_cli.compat import DeprecatedPath
  File "/home/basti/repos/streamlink/src/streamlink_cli/compat.py", line 6, in <module>
    stdout: BinaryIO = sys.stdout.buffer
                       ^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'buffer'

PR

$ streamlink >&-
usage: streamlink [OPTIONS] <URL> [STREAM]

Use -h/--help to see the available options or read the manual at https://streamlink.github.io
$ streamlink --stdout httpstream://file:///dev/zero best >&-
[cli][info] Found matching plugin http for URL httpstream://file:///dev/zero
[cli][info] Available streams: live (worst, best)
[cli][info] Opening stream: live (http)
^C[cli][info] Stream ended
Interrupted! Exiting...
[cli][info] Closing currently open stream...

Removing stderr as well is currently unsupported, and the process will stop because of a failure of the logging / console output setup, which falls back to stderr if stdout is None. Maybe I'll have a look at this later, too.

$ streamlink >&- 2>&-; echo $?
1

@bastimeyer bastimeyer force-pushed the cli/missing-stdout-fallback branch from 3cf5eb0 to 819b581 Compare September 23, 2024 22:54
@bastimeyer bastimeyer force-pushed the cli/missing-stdout-fallback branch from 819b581 to 633aa8f Compare September 23, 2024 23:09
@bastimeyer
Copy link
Member Author

No stdout/stderr

$ streamlink >&- 2>&-; echo $?
0
$ streamlink -l debug --logfile /tmp/log >&- 2>&- && cat /tmp/log
[cli][debug] OS:         Linux-6.11.0-1-git-x86_64-with-glibc2.40
[cli][debug] Python:     3.12.6
[cli][debug] OpenSSL:    OpenSSL 3.3.2 3 Sep 2024
[cli][debug] Streamlink: 6.10.0+34.g633aa8f4
[cli][debug] Dependencies:
[cli][debug]  certifi: 2024.8.30
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 5.3.0
[cli][debug]  pycountry: 24.6.1
[cli][debug]  pycryptodome: 3.20.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.32.3
[cli][debug]  trio: 0.26.2
[cli][debug]  trio-websocket: 0.12.0.dev0
[cli][debug]  typing-extensions: 4.12.2
[cli][debug]  urllib3: 2.2.3
[cli][debug]  websocket-client: 1.8.0
[cli][debug] Arguments:
[cli][debug]  --loglevel=debug
[cli][debug]  --logfile=/tmp/log
[cli][debug]  --player=/usr/bin/mpv
[cli][debug]  --webbrowser-headless=True
usage: streamlink [OPTIONS] <URL> [STREAM]

Use -h/--help to see the available options or read the manual at https://streamlink.github.io
$ streamlink -o /tmp/foo -f --hls-duration=10 URL best >&- 2>&- \
  && ffprobe -v error -of json -show_streams /tmp/foo | jq -r ".streams[0].duration"
9.984567

@bastimeyer bastimeyer marked this pull request as ready for review September 23, 2024 23:13
@bastimeyer bastimeyer merged commit 65d49fb into streamlink:master Sep 23, 2024
25 checks passed
@bastimeyer bastimeyer deleted the cli/missing-stdout-fallback branch September 23, 2024 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant