Migrating from Legacy Systems

Python Skills Checklist for Test Engineers

Learn the five Python skills a test engineer needs on a production floor, how to verify each in an interview or in week one, and what to leave off the list.

JJulien Buteau
beginner7 min readSeptember 23, 2026

"Knows Python" on a test floor means five specific things: talk to an instrument, survive a hardware failure without crashing the station, run the code on a station PC that isn't a laptop, use Git for changes and releases, and get a run with measurements and limits into TofuPilot. Everything else is optional. This checklist lists the five, what each looks like at the bench, and how to verify it in an interview or in week one.

The Five Skills

Print the table. Tick it in the interview, then tick it again on the Friday of week one. A candidate who's honest about a gap is more useful than one who claims all five.

SkillWhat it looks like in practiceHow to verify
Instrument I/O (PyVISA, SCPI, serial)Opens a resource by VISA address, sends *IDN?, parses the reply into a float. Knows write, query and read are three different things. Has used pyserial for a DUT console at 115200 baud.Interview: give them a DMM address and ask for a DC voltage read on the whiteboard. Week one: they write a plug for one bench instrument and it returns a number.
Exceptions around hardwareSets a timeout on every resource. Retries a flaky query a bounded number of times. Closes the instrument in close() even when the phase failed. Reports a VisaIOError as ERROR, not FAIL.Interview: ask what the station does when the DMM cable comes out mid-run. Week one: pull the cable during their phase and watch.
Packaging and environmentsCreates a venv, pins versions in requirements.txt, installs on a clean Windows station PC without editing PATH by hand. Knows "works on my laptop" isn't done.Interview: ask how they'd get code onto a station with no internet. Week one: they install their station on the spare PC from the README alone.
Git basicsBranches for a change, opens a pull request, gets a review, tags a release (v1.4.0) and can say which tag runs on which station.Interview: ask about the last thing they reverted and how. Week one: their first limit change lands as a reviewed pull request, not a file copied over the network share.
Data flowDeclares measurements with units and validators in procedure.yaml, runs with --upload, opens the run page for that unit in TofuPilot, reads FPY and Cpk on the procedure page instead of building a spreadsheet.Interview: ask what they'd open first when yield drops on a Monday. Week one: they find their own runs in TofuPilot and explain one Cpk value to you.

Three of the five are ordinary software hygiene. The two that separate a test engineer from a generalist developer are instrument I/O and hardware exceptions. Hire for those two and teach the other three during the first week.

Instrument I/O is the one to probe

Every other skill can be learned from a README. Instrument I/O needs a bench, an instrument that lies, and someone who's been bitten before. Ask about termination characters, about a query that returned the previous answer, about the difference between a GPIB timeout and a socket timeout.

The good candidates have a story for each. The PyVISA docs cover the mechanics, and a candidate who's read them will say so.

Exceptions are where stations die

A phase that raises and leaves the DMM half-configured costs you the next unit as well as this one. Ask for the three-part answer: timeout on open, bounded retry on read, cleanup on close.

A bare except that swallows the error is how a station reports PASS on a disconnected cable. Listen for whether the candidate knows the difference between a unit that failed and a station that errored.

What They Don't Need

A job description that lists everything Python can do filters out the people you want. The job description guide covers the posting itself. This is the short list of what to leave off.

Not neededWhy
GUI frameworks (Tkinter, Qt, a web front end)The operator UI is declared in the procedure: text inputs, checklists, images, sliders, progress. No frontend code on a station.
Building a sequencerThe framework runs phases in order, injects plugs, handles depends_on and multi-DUT slots. A home-made runner is the most common way to lose six months.
Building dashboardsFPY, Cpk, control charts, histograms and failure Pareto are in TofuPilot. A candidate who proposes a pandas notebook for yield is solving a problem you don't have.
LabVIEWUseful for reading the old station during a migration, not a hiring requirement. Your LabVIEW engineer walks them through the block diagram once.
Advanced Python (async, metaclasses, C extensions)A station is a folder of plain functions and plain classes. If it needs asyncio, the fixture design is the problem.

Every plant has one home-made yield dashboard that only opens on one PC, and the person who built it is on holiday.

Self-Assessment

Use this for a candidate after the take-home, or for a current engineer planning their own move from LabVIEW. Level 2 across the board is a working station owner. Level 3 in one or two rows is a lead.

SkillLevel 1Level 2Level 3
Instrument I/ORuns an existing plug and reads the valueWrites a new plug from the SCPI manual, handles termination and timeoutsDebugs a bus problem with a protocol trace, drives a multi-instrument fixture
Hardware exceptionsCatches the exception and logs itBounded retries, cleanup in close(), ERROR and FAIL reported correctlyDesigns the recovery path: power cycle the fixture, re-init, resume at the right phase
PackagingRuns from a venv on their own machineInstalls from requirements.txt on a station PC offlinePins the Python version, scripts the station install, keeps a known-good image
GitCommits to mainBranch, pull request, review, tagReviews others, bisects a regression, keeps one repo per station clean
Data flowUploads a run and finds it in TofuPilotDeclares limits in procedure.yaml, reads FPY and Cpk per procedureReads a drift on the control chart, ties it to a fixture or instrument, files the fix as a pull request

A LabVIEW developer moving to Python usually scores 3 on the ideas behind instrument I/O and exceptions from day one, and 1 on packaging and Git. That's a shorter gap than most managers expect.

Two Blocks Worth Reading

Both are the size of the real thing. If a candidate can read these and say what breaks when you remove any line, they pass the first two rows of the checklist.

A plug with a timeout, a bounded retry and cleanup in close():

plugs/dmm.py
26 lines
# Multimeter plug: timeout on open, bounded retry on read, cleanup in close().import pyvisaclass Multimeter:    def __init__(self, address="TCPIP::192.168.1.100::INSTR", retries=3):        self.rm = pyvisa.ResourceManager("@py")        self.inst = self.rm.open_resource(address)        self.inst.timeout = 2000  # milliseconds        self.retries = retries    def read_voltage(self):        last_error = None        for _ in range(self.retries):            try:                return float(self.inst.query(":MEAS:VOLT:DC?"))            except pyvisa.VisaIOError as error:                last_error = error        raise last_error    def close(self):        try:            self.inst.write("*RST")        finally:            self.inst.close()            self.rm.close()

The phase that uses it is two lines: def power_rails(measurements, dmm): measurements.rail_3v3 = dmm.read_voltage(). The limits don't live in the phase. They live here:

procedure.yaml
25 lines
# One phase, one measurement. Limits live in the procedure, not in the code.name: PCBA Functional Testversion: 1.4.0unit:  serial_number:    default_value: "SN-000001"  part_number:    default_value: "PCBA-100"plugs:  - name: dmm    python: plugs.dmm:Multimetermain:  - name: Power Rails    python: phases.power_rails    measurements:      - name: rail_3v3        unit: V        validators:          - operator: ">="            expected_value: 3.2          - operator: "<="            expected_value: 3.4

Run it with --upload and the measurement, its limits and its outcome land on the unit's run page in TofuPilot. The Cpk for rail_3v3 shows up on the procedure page once there are enough runs. Nobody writes that part.

Start With One Station

Pick the station with the highest volume, or the one only one person can open. Rebuild it in Python with the TofuPilot Framework, then run it side by side with the LabVIEW version on the same units for two weeks. The five skills above are exactly what that rebuild exercises, in order.

station-setup.sh
# Install the CLI, run a procedure locally, then run it with upload.curl -fsSL https://www.tofupilot.app/install | shtofupilot run ./procedure.yamltofupilot run ./procedure.yaml --upload

The LabVIEW migration guide covers the rebuild step by step, and the Framework page covers the layout. The Lab tier is free, and tofupilot run works with no account.

More Guides

Put this guide into practice