Skip to content

fix(pico): reject truncated SCPI responses and close the socket on a failed Wi-Fi connect - #291

Open
thisisanubhav wants to merge 3 commits into
fossasia:mainfrom
thisisanubhav:fix/pico-scpi-truncated-response
Open

thisisanubhav wants to merge 3 commits into
fossasia:mainfrom
thisisanubhav:fix/pico-scpi-truncated-response

Conversation

@thisisanubhav

@thisisanubhav thisisanubhav commented Sep 22, 2026 •

Copy link
Copy Markdown

Fixes #290

Changes

  • ScpiClient.query() now requires the response to end with \n, and raises ScpiTimeoutError otherwise. On USB, pyserial's readline() returns whatever arrived before the timeout, so a cut-off "12" of "123\n" used to be returned as a valid answer. The Wi-Fi transport already behaved this way. The text error line in read_block() gets the same check.
  • PicoWifiTransport.connect() closes the socket if connect() raises, instead of leaking one socket per failed attempt.
  • Tests for both, using the existing fakes in tests/test_pico_scpi_transport.py.

Testing

  • pytest tests/test_pico_scpi_transport.py: 21 passed. Against main's transport.py, the 3 new tests fail.
  • flake8 is clean on the changed files. pslab/pico isn't in the tox lint set, and black --check already flags one line there on main; I left that untouched to keep the diff focused.

No UI changes.

Summary by Sourcery

Ensure incomplete SCPI responses time out and failed Wi-Fi connections release their sockets.

Bug Fixes:

  • Reject truncated SCPI query and error responses that do not end with a newline.
  • Close Wi-Fi sockets when connection attempts fail to prevent resource leaks.

Tests:

  • Add coverage for truncated SCPI responses and failed Wi-Fi connection cleanup.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of interrupted or incomplete SCPI responses by reporting timeouts accurately.
    • Correctly distinguishes communication timeouts from valid SCPI error responses.
    • Ensured failed Wi-Fi connection attempts clean up the underlying connection properly.
  • Tests

    • Added coverage for incomplete responses, timeout reporting, and connection cleanup during failed connection attempts.

pyserial's readline() returns whatever arrived before the timeout, so a
response cut off mid-line ("12" of "123\n") was returned by query() as
a complete answer. Require the line terminator in query() and in the
text error line read by read_block(), and raise ScpiTimeoutError
otherwise, which is what the Wi-Fi transport already does.
PicoWifiTransport.connect() left the socket open if connect() raised
(connection refused or timed out), leaking one socket per attempt
against an unreachable bridge.
@sourcery-ai

sourcery-ai Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

The PR hardens Pico SCPI and Wi-Fi transport failure handling by rejecting unterminated responses as timeouts and closing sockets when connection setup fails, with focused regression coverage using the existing test fakes.

Sequence diagram for truncated SCPI response handling

sequenceDiagram
    participant Client as ScpiClient
    participant Transport as SCPI transport

    Client->>Transport: readline()
    alt response ends with newline
        Transport-->>Client: response bytes
        Client-->>Client: decode and strip
    else response is truncated
        Transport-->>Client: partial bytes
        Client-->>Client: raise ScpiTimeoutError
    end
Loading

Sequence diagram for failed Wi-Fi connection cleanup

sequenceDiagram
    participant Client as PicoWifiTransport
    participant Socket as Wi-Fi socket

    Client->>Socket: socket()
    Client->>Socket: settimeout(timeout)
    Client->>Socket: connect(host, port)
    alt connection succeeds
        Client->>Client: store socket
    else connect() raises
        Client->>Socket: close()
        Client-->>Client: re-raise exception
    end
Loading

File-Level Changes

Change Details Files
Require complete newline-terminated SCPI responses before returning or decoding them.
  • Reject truncated query responses with ScpiTimeoutError.
  • Apply the same completeness check to non-block error lines in read_block().
  • Add regression tests for truncated query and block-error responses.
pslab/pico/transport.py
tests/test_pico_scpi_transport.py
Ensure failed Wi-Fi connection attempts release their socket resources.
  • Close the newly created socket when setup or connect raises, then re-raise the original exception.
  • Add a test verifying the socket closes and the transport remains unopened.
pslab/pico/transport.py
tests/test_pico_scpi_transport.py

Assessment against linked issues

Issue Objective Addressed Explanation
#290 Ensure SCPI responses read by ScpiClient.query and error lines read by read_block are rejected with ScpiTimeoutError when they do not include the terminating newline. ✅
#290 Ensure PicoWifiTransport.connect closes the newly created socket when setting it up or connecting fails, then re-raises the original exception. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 455eb943-0cb8-4d98-8b7b-af4dc117f9f8

📥 Commits

Reviewing files that changed from the base of the PR and between 08de0d0 and 939c661.

📒 Files selected for processing (2)
  • pslab/pico/transport.py
  • tests/test_pico_scpi_transport.py

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

ScpiClient now rejects truncated responses as timeouts. read_block() distinguishes incomplete responses from complete SCPI errors. PicoWifiTransport.connect() closes its socket before re-raising setup failures. Tests cover both behaviors.

Changes

Transport error handling

Layer / File(s) Summary
SCPI response completeness
pslab/pico/transport.py, tests/test_pico_scpi_transport.py
query() and read_block() raise ScpiTimeoutError for responses without a newline terminator. Complete error lines still raise ScpiError. Tests simulate truncated responses.
Wi-Fi socket failure cleanup
pslab/pico/transport.py, tests/test_pico_scpi_transport.py
connect() closes the socket when setup fails and re-raises the original exception. The test verifies the socket and transport remain closed.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~15 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 939c6

The transport now rejects incomplete SCPI responses and closes sockets after failed Wi-Fi setup. No concrete production risk blocks merging this change.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes both main changes: rejecting truncated SCPI responses and closing the socket after a failed Wi-Fi connection.
Linked Issues check ✅ Passed Issue #290 requires rejection of unterminated SCPI responses and socket cleanup after failed Wi-Fi connects. ScpiClient.query() and the text-error path in read_block() now raise ScpiTimeoutError…
Out of Scope Changes check ✅ Passed The changes are limited to pslab/pico/transport.py and related tests. The production changes implement both objectives in issue #290. The added tests directly verify the required behavior. No unrela…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pico SCPI: a truncated response is accepted as complete, and a failed Wi-Fi connect leaks its socket

1 participant