[typ] Capture subprocess stdio [catapult : main]

1 view
Skip to first unread message

Jonathan Lee (Gerrit)

unread,
Nov 7, 2025, 11:07:10 PM (6 days ago) Nov 7
to Brian Sheedy, AyeAye, Catapult LUCI CQ, catapult...@chromium.org, telemetr...@chromium.org
Attention needed from Brian Sheedy

Jonathan Lee added 1 comment

Patchset-level comments
File-level comment, Patchset 8 (Latest):
Jonathan Lee . resolved

Tested downstream: https://crrev.com/c/7129507

Seems to work on all platforms:

Open in Gerrit

Related details

Attention is currently required from:
  • Brian Sheedy
Submit Requirements:
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: catapult
Gerrit-Branch: main
Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
Gerrit-Change-Number: 7124053
Gerrit-PatchSet: 8
Gerrit-Owner: Jonathan Lee <jonath...@google.com>
Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
Gerrit-Attention: Brian Sheedy <bsh...@chromium.org>
Gerrit-Comment-Date: Sat, 08 Nov 2025 04:07:07 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
unsatisfied_requirement
open
diffy

Brian Sheedy (Gerrit)

unread,
Nov 10, 2025, 1:04:12 PM (3 days ago) Nov 10
to Jonathan Lee, AyeAye, Catapult LUCI CQ, catapult...@chromium.org, telemetr...@chromium.org
Attention needed from Jonathan Lee

Brian Sheedy added 1 comment

File third_party/typ/typ/host.py
Line 255, Patchset 8 (Latest): # Set up redirection lazily so that `sys.std(out|err)` remains unaltered
Brian Sheedy . unresolved

I believe this won't work correctly for GPU tests which use the browser instance that is created during `SetUpProcess()`, e.g. [here](https://source.chromium.org/chromium/chromium/src/+/main:content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py;l=252)

This is called once per child process when setting up the pool [here](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=665), but `capture_output` is called [once for every test that is run](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=1191).

This should resolve itself when the browser is restarted, but we want consistent behavior regardless of when a test happens to run.

Open in Gerrit

Related details

Attention is currently required from:
  • Jonathan Lee
Submit Requirements:
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: catapult
    Gerrit-Branch: main
    Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
    Gerrit-Change-Number: 7124053
    Gerrit-PatchSet: 8
    Gerrit-Owner: Jonathan Lee <jonath...@google.com>
    Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
    Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
    Gerrit-Attention: Jonathan Lee <jonath...@google.com>
    Gerrit-Comment-Date: Mon, 10 Nov 2025 18:04:09 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    unsatisfied_requirement
    open
    diffy

    Jonathan Lee (Gerrit)

    unread,
    Nov 10, 2025, 7:51:21 PM (3 days ago) Nov 10
    to Brian Sheedy, AyeAye, Catapult LUCI CQ, catapult...@chromium.org, telemetr...@chromium.org
    Attention needed from Brian Sheedy

    Jonathan Lee added 3 comments

    Patchset-level comments
    Jonathan Lee

    This time, I checked the test results for `expected_color` tests. In PS8, the `chrome` log was missing from the first few tests, but aren't anymore:

    • [Linux]
    • [macOS]
    • [Windows]

    [Linux]: https://luci-milo.appspot.com/ui/inv/task-chromium-swarm.appspot.com-74892d2046de4811/test-results
    [macOS]: https://luci-milo.appspot.com/ui/inv/task-chromium-swarm.appspot.com-74890cb0e98cb611/test-results
    [Windows]: https://luci-milo.appspot.com/ui/inv/task-chromium-swarm.appspot.com-74892ba10e757811/test-results

    File telemetry/telemetry/internal/backends/chrome/desktop_browser_backend.py
    Line 217, Patchset 11 (Parent): cmd, stdout=sys.stdout, stderr=sys.stderr, env=env)
    Jonathan Lee . resolved

    For Windows, `desktop_browser_backend.py` must pass FDs 1/2 to the `chrome` process. Passing the `alt_fd`s doesn't seem to work (see https://crrev.com/c/7124053/6, tested [here]).

    In PS8, `desktop_browser_backend.py` implicitly honored this because `sys.std(out|err)` was either:
    1. A `_TeedStream` (fell back to `sys.__std(out|err)__` via `io.UnsupportedOperation`)
    2. The original `sys.std(out|err) is sys.__std(out|err)__`

    However, in the new `runner._setup_process`, this `sys.std(out|err)` can now be the stream backed by `alt_fd`, so we need to pass `sys.__std(out|err)__` directly now.

    [here]: https://ci.chromium.org/ui/p/chromium/builders/try/gpu-fyi-try-win10-nvidia-rel-64/658/overview

    File third_party/typ/typ/host.py
    Line 255, Patchset 8: # Set up redirection lazily so that `sys.std(out|err)` remains unaltered
    Brian Sheedy . resolved

    I believe this won't work correctly for GPU tests which use the browser instance that is created during `SetUpProcess()`, e.g. [here](https://source.chromium.org/chromium/chromium/src/+/main:content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py;l=252)

    This is called once per child process when setting up the pool [here](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=665), but `capture_output` is called [once for every test that is run](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=1191).

    This should resolve itself when the browser is restarted, but we want consistent behavior regardless of when a test happens to run.

    Jonathan Lee

    I see. Changed to expose and rename `{init => setup}_stdio_for_process` and call that from `runner._setup_process` in the necessary order.

    I don't think we should reassign `sys.std*` in `Host.__init__`, since web tests need a `typ.host.Host` instance to use with `typ.artifacts.Artifacts`, but the web test runners don't call `capture_ouptut()` and don't need `sys.std*` redirection.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Brian Sheedy
    Submit Requirements:
      • requirement is not satisfiedCode-Owners
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: catapult
      Gerrit-Branch: main
      Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
      Gerrit-Change-Number: 7124053
      Gerrit-PatchSet: 11
      Gerrit-Owner: Jonathan Lee <jonath...@google.com>
      Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
      Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
      Gerrit-Attention: Brian Sheedy <bsh...@chromium.org>
      Gerrit-Comment-Date: Tue, 11 Nov 2025 00:51:18 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Jonathan Lee <jonath...@google.com>
      Comment-In-Reply-To: Brian Sheedy <bsh...@chromium.org>
      unsatisfied_requirement
      open
      diffy

      Brian Sheedy (Gerrit)

      unread,
      Nov 10, 2025, 8:22:10 PM (3 days ago) Nov 10
      to Jonathan Lee, AyeAye, Catapult LUCI CQ, catapult...@chromium.org, telemetr...@chromium.org
      Attention needed from Jonathan Lee

      Brian Sheedy added 2 comments

      File third_party/typ/typ/host.py
      Line 255, Patchset 8: # Set up redirection lazily so that `sys.std(out|err)` remains unaltered
      Brian Sheedy . unresolved

      I believe this won't work correctly for GPU tests which use the browser instance that is created during `SetUpProcess()`, e.g. [here](https://source.chromium.org/chromium/chromium/src/+/main:content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py;l=252)

      This is called once per child process when setting up the pool [here](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=665), but `capture_output` is called [once for every test that is run](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=1191).

      This should resolve itself when the browser is restarted, but we want consistent behavior regardless of when a test happens to run.

      Jonathan Lee

      I see. Changed to expose and rename `{init => setup}_stdio_for_process` and call that from `runner._setup_process` in the necessary order.

      I don't think we should reassign `sys.std*` in `Host.__init__`, since web tests need a `typ.host.Host` instance to use with `typ.artifacts.Artifacts`, but the web test runners don't call `capture_ouptut()` and don't need `sys.std*` redirection.

      Brian Sheedy

      Not doing this in `__init__` SGTM.

      I'm still seeing some unexpected behavior around tests that use the first launched browser, though.

      In your linked `expected_color` examples, the first test to run (`ExpectedColor_MediaRecorderFrom2DCanvas`) does not have any logging captured for browser startup. However, the third test (`ExpectedColor_maps`) does, as it restarts the browser to pick up different browser args.

      I don't think this is a big enough issue to block submission until it's fully fixed, but it would be good to do some investigation into why this is the case. If you're unable to track down the root cause quickly or if the fix isn't simple, then I think it's fine to add a TODO and come back to this later.

      Line 332, Patchset 11 (Latest): getattr(sys, stream_name).write(line)
      Brian Sheedy . unresolved

      Nit: Perhaps this isn't called frequently enough to actually matter, but it seems wasteful to look up the stream every single time we write a line. At this point, is `sys.std(out|err)` ever expected to be replaced out from under the forwarder? If not, then it seems like it would be better to to `stream = getattr(sys, stream_name)` at the top of the function and use that.

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Jonathan Lee
      Submit Requirements:
        • requirement is not satisfiedCode-Owners
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: catapult
        Gerrit-Branch: main
        Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
        Gerrit-Change-Number: 7124053
        Gerrit-PatchSet: 11
        Gerrit-Owner: Jonathan Lee <jonath...@google.com>
        Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
        Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
        Gerrit-Attention: Jonathan Lee <jonath...@google.com>
        Gerrit-Comment-Date: Tue, 11 Nov 2025 01:22:08 +0000
        unsatisfied_requirement
        open
        diffy

        Brian Sheedy (Gerrit)

        unread,
        Nov 10, 2025, 8:58:58 PM (3 days ago) Nov 10
        to Jonathan Lee, AyeAye, Catapult LUCI CQ, catapult...@chromium.org, telemetr...@chromium.org
        Attention needed from Jonathan Lee

        Brian Sheedy added 1 comment

        File third_party/typ/typ/host.py
        Line 255, Patchset 8: # Set up redirection lazily so that `sys.std(out|err)` remains unaltered
        Brian Sheedy . unresolved

        I believe this won't work correctly for GPU tests which use the browser instance that is created during `SetUpProcess()`, e.g. [here](https://source.chromium.org/chromium/chromium/src/+/main:content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py;l=252)

        This is called once per child process when setting up the pool [here](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=665), but `capture_output` is called [once for every test that is run](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=1191).

        This should resolve itself when the browser is restarted, but we want consistent behavior regardless of when a test happens to run.

        Jonathan Lee

        I see. Changed to expose and rename `{init => setup}_stdio_for_process` and call that from `runner._setup_process` in the necessary order.

        I don't think we should reassign `sys.std*` in `Host.__init__`, since web tests need a `typ.host.Host` instance to use with `typ.artifacts.Artifacts`, but the web test runners don't call `capture_ouptut()` and don't need `sys.std*` redirection.

        Brian Sheedy

        Not doing this in `__init__` SGTM.

        I'm still seeing some unexpected behavior around tests that use the first launched browser, though.

        In your linked `expected_color` examples, the first test to run (`ExpectedColor_MediaRecorderFrom2DCanvas`) does not have any logging captured for browser startup. However, the third test (`ExpectedColor_maps`) does, as it restarts the browser to pick up different browser args.

        I don't think this is a big enough issue to block submission until it's fully fixed, but it would be good to do some investigation into why this is the case. If you're unable to track down the root cause quickly or if the fix isn't simple, then I think it's fine to add a TODO and come back to this later.

        Brian Sheedy

        Ah, it's because even if we swap out stdio, we don't start capturing until the test actually starts.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Jonathan Lee
        Submit Requirements:
        • requirement is not satisfiedCode-Owners
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: catapult
        Gerrit-Branch: main
        Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
        Gerrit-Change-Number: 7124053
        Gerrit-PatchSet: 11
        Gerrit-Owner: Jonathan Lee <jonath...@google.com>
        Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
        Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
        Gerrit-Attention: Jonathan Lee <jonath...@google.com>
        Gerrit-Comment-Date: Tue, 11 Nov 2025 01:58:56 +0000
        unsatisfied_requirement
        open
        diffy

        Brian Sheedy (Gerrit)

        unread,
        Nov 10, 2025, 9:15:04 PM (3 days ago) Nov 10
        to Jonathan Lee, AyeAye, Catapult LUCI CQ, catapult...@chromium.org, telemetr...@chromium.org
        Attention needed from Jonathan Lee

        Brian Sheedy voted and added 2 comments

        Votes added by Brian Sheedy

        Code-Review+1

        2 comments

        Patchset-level comments
        File-level comment, Patchset 11 (Latest):
        Brian Sheedy . resolved

        LGTM % nit

        File third_party/typ/typ/host.py
        Line 255, Patchset 8: # Set up redirection lazily so that `sys.std(out|err)` remains unaltered
        Brian Sheedy . resolved

        I believe this won't work correctly for GPU tests which use the browser instance that is created during `SetUpProcess()`, e.g. [here](https://source.chromium.org/chromium/chromium/src/+/main:content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py;l=252)

        This is called once per child process when setting up the pool [here](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=665), but `capture_output` is called [once for every test that is run](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/typ/typ/runner.py;l=1191).

        This should resolve itself when the browser is restarted, but we want consistent behavior regardless of when a test happens to run.

        Jonathan Lee

        I see. Changed to expose and rename `{init => setup}_stdio_for_process` and call that from `runner._setup_process` in the necessary order.

        I don't think we should reassign `sys.std*` in `Host.__init__`, since web tests need a `typ.host.Host` instance to use with `typ.artifacts.Artifacts`, but the web test runners don't call `capture_ouptut()` and don't need `sys.std*` redirection.

        Brian Sheedy

        Not doing this in `__init__` SGTM.

        I'm still seeing some unexpected behavior around tests that use the first launched browser, though.

        In your linked `expected_color` examples, the first test to run (`ExpectedColor_MediaRecorderFrom2DCanvas`) does not have any logging captured for browser startup. However, the third test (`ExpectedColor_maps`) does, as it restarts the browser to pick up different browser args.

        I don't think this is a big enough issue to block submission until it's fully fixed, but it would be good to do some investigation into why this is the case. If you're unable to track down the root cause quickly or if the fix isn't simple, then I think it's fine to add a TODO and come back to this later.

        Brian Sheedy

        Ah, it's because even if we swap out stdio, we don't start capturing until the test actually starts.

        Brian Sheedy

        In that case, I think it's fine to stick with the current behavior since it expected behavior. We don't care too much about the browser startup output and it'll be easy enough to find in the Swarming task if it's actually needed.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Jonathan Lee
        Submit Requirements:
        • requirement satisfiedCode-Owners
        • requirement satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement satisfiedReview-Enforcement
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: catapult
        Gerrit-Branch: main
        Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
        Gerrit-Change-Number: 7124053
        Gerrit-PatchSet: 11
        Gerrit-Owner: Jonathan Lee <jonath...@google.com>
        Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
        Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
        Gerrit-Attention: Jonathan Lee <jonath...@google.com>
        Gerrit-Comment-Date: Tue, 11 Nov 2025 02:15:02 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: Yes
        satisfied_requirement
        unsatisfied_requirement
        open
        diffy

        Jonathan Lee (Gerrit)

        unread,
        Nov 11, 2025, 2:09:22 PM (2 days ago) Nov 11
        to Brian Sheedy, AyeAye, Catapult LUCI CQ, catapult...@chromium.org, telemetr...@chromium.org

        Jonathan Lee voted and added 1 comment

        Votes added by Jonathan Lee

        Commit-Queue+2

        1 comment

        File third_party/typ/typ/host.py
        Line 332, Patchset 11: getattr(sys, stream_name).write(line)
        Brian Sheedy . resolved

        Nit: Perhaps this isn't called frequently enough to actually matter, but it seems wasteful to look up the stream every single time we write a line. At this point, is `sys.std(out|err)` ever expected to be replaced out from under the forwarder? If not, then it seems like it would be better to to `stream = getattr(sys, stream_name)` at the top of the function and use that.

        Jonathan Lee

        This is actually needed for correctness, since `sys.std(out|err)` can switch between `alt_stream` and `_TeedStream(alt_stream)` over the process's lifetime as the `Host` captures/restores. Reworded the comment to hopefully make that clearer.

        Regarding performance, [this benchmark] claims `getattr()` is 2x slower than a theoretically optimal direct access, but both seem negligible relative [to `TextIOWrapper.write()`][0] and all of the underlying buffering machinery. Also, the `getattr()` cost is bounded by how frequently the subprocesses are producing lines, which shouldn't be that frequent except in pathological cases like invoking the `yes` binary.

        [0]: https://github.com/python/cpython/blob/92741c59f89e114474bdb2cb539107ef6bae0b9c/Lib/_pyio.py#L2269
        [this benchmark]: https://stackoverflow.com/a/41129351

        Open in Gerrit

        Related details

        Attention set is empty
        Submit Requirements:
          • requirement satisfiedCode-Owners
          • requirement satisfiedCode-Review
          • requirement satisfiedReview-Enforcement
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: catapult
          Gerrit-Branch: main
          Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
          Gerrit-Change-Number: 7124053
          Gerrit-PatchSet: 12
          Gerrit-Owner: Jonathan Lee <jonath...@google.com>
          Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
          Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
          Gerrit-Comment-Date: Tue, 11 Nov 2025 19:09:20 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: Yes
          Comment-In-Reply-To: Brian Sheedy <bsh...@chromium.org>
          satisfied_requirement
          open
          diffy

          Jonathan Lee (Gerrit)

          unread,
          Nov 11, 2025, 6:52:13 PM (2 days ago) Nov 11
          to Brian Sheedy, AyeAye, Catapult LUCI CQ, catapult...@chromium.org, telemetr...@chromium.org

          Jonathan Lee voted Commit-Queue+2

          Commit-Queue+2
          Open in Gerrit

          Related details

          Attention set is empty
          Submit Requirements:
          • requirement satisfiedCode-Owners
          • requirement satisfiedCode-Review
          • requirement satisfiedReview-Enforcement
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: catapult
          Gerrit-Branch: main
          Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
          Gerrit-Change-Number: 7124053
          Gerrit-PatchSet: 12
          Gerrit-Owner: Jonathan Lee <jonath...@google.com>
          Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
          Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
          Gerrit-Comment-Date: Tue, 11 Nov 2025 23:52:11 +0000
          Gerrit-HasComments: No
          Gerrit-Has-Labels: Yes
          satisfied_requirement
          open
          diffy

          Catapult LUCI CQ (Gerrit)

          unread,
          Nov 11, 2025, 7:10:48 PM (2 days ago) Nov 11
          to Jonathan Lee, Brian Sheedy, AyeAye, catapult...@chromium.org, telemetr...@chromium.org

          Catapult LUCI CQ submitted the change with unreviewed changes

          Unreviewed changes

          11 is the latest approved patch-set.
          The change was submitted with unreviewed changes in the following files:

          ```
          The name of the file: third_party/typ/typ/host.py
          Insertions: 6, Deletions: 5.

          @@ -324,11 +324,12 @@
          encoding = getattr(sys, stream_name).encoding
          with os.fdopen(read_fd, encoding=encoding, newline='') as reader:
          for line in reader:
          - # For nested `_TeedStream`s, send the line to the current
          - # outermost stream and let the write propagate inward towards the
          - # backing OS stream. These writes are line-buffered and mutually
          - # exclusive with other threads, so the captured output won't have
          - # interwoven line fragments.
          + # `sys.std(out|err)` can switch at any point between the
          + # `alt_stream` created in `_remap_stream()` and
          + # `_TeedStream(alt_stream)` when capturing. Therefore, we need to
          + # resolve the current stream for each write. These writes are
          + # line-buffered and mutually exclusive with other threads, so the
          + # captured output won't have interwoven line fragments.
          getattr(sys, stream_name).write(line)


          ```

          Change information

          Commit message:
          [typ] Capture subprocess stdio

          When initializing a typ runner child process, permanently replace the
          `STD(OUT|ERR)_FILENO` file descriptors with a pipe that subprocesses can
          inherit. A helper thread forwards lines from the pipe to
          `sys.std(out|err).write()`, which is either:
          * The remapped std(out|err) object
          * One or more wrapping `_TeedStream`s, which have been made threadsafe

          Remapping is how real shells implement file redirection (e.g.,
          `>/path/to/file`).
          Bug: 40231966
          Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
          Reviewed-by: Brian Sheedy <bsh...@chromium.org>
          Commit-Queue: Jonathan Lee <jonath...@google.com>
          Files:
          • M telemetry/telemetry/internal/backends/chrome/desktop_browser_backend.py
          • M third_party/typ/typ/host.py
          • M third_party/typ/typ/runner.py
          • M third_party/typ/typ/tests/main_test.py
          Change size: M
          Delta: 4 files changed, 131 insertions(+), 35 deletions(-)
          Branch: refs/heads/main
          Submit Requirements:
          • requirement satisfiedCode-Review: +1 by Brian Sheedy
          Open in Gerrit
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: merged
          Gerrit-Project: catapult
          Gerrit-Branch: main
          Gerrit-Change-Id: I7fb28f13910285fd0c2fb8b9b5c1451974eec68d
          Gerrit-Change-Number: 7124053
          Gerrit-PatchSet: 13
          Gerrit-Owner: Jonathan Lee <jonath...@google.com>
          Gerrit-Reviewer: Brian Sheedy <bsh...@chromium.org>
          Gerrit-Reviewer: Catapult LUCI CQ <catapul...@luci-project-accounts.iam.gserviceaccount.com>
          Gerrit-Reviewer: Jonathan Lee <jonath...@google.com>
          open
          diffy
          satisfied_requirement
          Reply all
          Reply to author
          Forward
          0 new messages