type(subprocess.Popen(<some_args>).stdout) is None

Hi!

I’m writing an application in python and I’m having some troubles with capturing output from subprocess command.

This is my repo:

Commit as of time of writing: 180b21b9e8c1e908ed684678ca8d0fe606cb109d.

The problem is in router function() in fuujin/fuujin_lib/core_functions.py. This is how it looks:

def router(variables):
    from time import sleep
    import subprocess
    from .init_functions import logger

    debug_level = variables["debug_level"]
    logger(debug_level=debug_level,debug_level_of_text=2,text="this is router module!")

    proc = subprocess.Popen(
        ["ping", "google.com"],
        stdout=subprocess.PIPE,   # Capture stdout
        stderr=subprocess.STDOUT, # merge stderr into stdout
        text=True,                # Return strings instead of bytes
        bufsize=1,                # Line‑buffered (helps with real‑time output)
    )
    # Iterate over each line as soon as the child writes it
    for line in proc.stdout:
        text = "router output: " + line.rstrip()
        logger(debug_level=debug_level,text=text,debug_level_of_text=1)
    proc.poll()
    print("Process finished with return code:", proc.wait()) # exit code

This function is called by fuujin/main.py upon passing argument “–only-router” and passing “-c ./test/” (config file, it will freak out without it, I didn’t fix it yet). To build and run it:

user@kaktus ~ (main)> nix build .#fuujin
user@kaktus ~ (main)> fuujin --only-router -c ./test/
2026-01-04 13:26:44.308387 --> master: False
2026-01-04 13:26:44.308411 --> worker: False
2026-01-04 13:26:44.308418 --> manager: False
2026-01-04 13:26:44.308424 --> only_router: True
2026-01-04 13:26:44.308430 --> config_path: ./test/
2026-01-04 13:26:44.308434 --> debug_level: 2
2026-01-04 13:26:44.308438 --> language: en
2026-01-04 13:26:44.308443 --> native_host: False
2026-01-04 13:26:44.308447 --> manager.gui: True
2026-01-04 13:26:44.308451 --> manager.web_interface: True
2026-01-04 13:26:44.308456 --> 
: 
2026-01-04 13:26:44.308463 --> master.router: True
2026-01-04 13:26:44.317242 --> this is router module!
^CException ignored in atexit callback <function _exit_function at 0x7ffff69b85e0>:
Traceback (most recent call last):
  File "/nix/store/qzc04a3npl70cyyy6flnnrb2ig3kayxm-python3-3.13.11/lib/python3.13/multiprocessing/util.py", line 428, in _exit_function
    p.join()
  File "/nix/store/qzc04a3npl70cyyy6flnnrb2ig3kayxm-python3-3.13.11/lib/python3.13/multiprocessing/process.py", line 149, in join
    res = self._popen.wait(timeout)
  File "/nix/store/qzc04a3npl70cyyy6flnnrb2ig3kayxm-python3-3.13.11/lib/python3.13/multiprocessing/popen_fork.py", line 44, in wait
    return self.poll(os.WNOHANG if timeout == 0.0 else 0)
  File "/nix/store/qzc04a3npl70cyyy6flnnrb2ig3kayxm-python3-3.13.11/lib/python3.13/multiprocessing/popen_fork.py", line 28, in poll
    pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt: 
Process Process-1:
Traceback (most recent call last):
  File "/nix/store/qzc04a3npl70cyyy6flnnrb2ig3kayxm-python3-3.13.11/lib/python3.13/multiprocessing/process.py", line 313, in _bootstrap
    self.run()
    ~~~~~~~~^^
  File "/nix/store/qzc04a3npl70cyyy6flnnrb2ig3kayxm-python3-3.13.11/lib/python3.13/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/3q3w9wb49xj22b8n3f18g5qq6a0db0wi-fuujin-0.1.0/lib/python3.13/site-packages/fuujin/fuujin_lib/core_functions.py", line 47, in router
    for line in proc.stdout:
                ^^^^^^^^^^^
KeyboardInterrupt
user@kaktus ~ (main)>

After this line: 2026-01-04 13:26:44.317242 --> this is router module! I had to interrupt it.

What I expect:

running this program should result in running ping command, but somehow proc.stdout is of type None as shown by pyright:

What am I doing wrong here? I would be grateful for any help!

Best,
Miro

PS. If I’m doing some stupid stuff in my code please let me know!

Doesn’t it work with subprocess.run and capture_output=True, instead of Popen?

Pyright is telling you that proc.stdout might be None, and if it is, it can’t be used as an iterable. (Currently, type checkers don’t know how to make the connection between stdout=subprocess.PIPE and whether proc.stdout is None or not.)

Are you sure that your logger is configured correctly? I’m not sure what debug_level_of_text is, but for the stdout lines you set it to 1, while for "this is router module!" you set it to 2. Could it be that the logs you’re expecting are being filtered out?

1 Like

If ping is called without the -c option, it’ll ping forever, so the Python code will never leave the for loop.

Also, the proc.poll() is pointless because it simply checks whether the subprocess has terminated and then returns immediately.

That was it! Thank you, logger() will output only if debug_level_of_text is equal or greater than debug_level which is only when using -v option (or one of these: -d 1 / -d 0).