It looks like EbuildPhase._start_ebuild(), which gets called by _spawn_phase does use its own fd_pipes dict and the one passed to _spawn_phase isn't actually used.
This is quite a big problem for Sabayon Entropy because we are no longer able to log portage.doebuild() output and have users file proper and complete bug report info.
I would like to be able to tell Portage where to write its stuff through portage.doebuild() so that I can redirect the output to a log file (and write it to stdout/stderr myself).
I've done some cleanup on the returnpid support, and updated the docstring to mention that fd_pipes parameter is only guaranteed to be respected when returnpid is True (otherwise all subprocesses simply inherit file descriptors from sys.__std* streams):
I've also disabled the global spawned_pids list and made it so that it will not throw a ValueError if you try to remove a pid from the (always empty) list:
I plan to add support for fd_pipes with returnpid=False, since it's preferable to use returnpid=False at least because it allows portage to do IPC with the ebuild process (for things like best/has_version and die calls).
Some phases have important hooks that are built into the EbuildPhase class, and those hooks won't run in use call doebuild with returnpid=True. So, it seems like we should deprecate the returnpid parameter.
Support fd_pipes with returnpid=False:
Deprecate returnpid as discussed in comment #2 and comment #3:
This is fixed in 126.96.36.199 and 2.2.0_alpha187.