Skip to content

Commit b8d7064

Browse files
committed
remove tests, change implementation
1 parent 751e912 commit b8d7064

2 files changed

Lines changed: 38 additions & 42 deletions

File tree

src/probeinterface/neuropixels_tools.py

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,50 +1601,65 @@ def read_openephys(*args, **kwargs) -> Probe:
16011601
return read_openephys_neuropixels(*args, **kwargs)
16021602

16031603

1604+
_NP_PROBE_ELEMENT_TAGS = frozenset(
1605+
{"NP_PROBE", "NEUROPIXELSV1E", "NEUROPIXELSV1F", "NEUROPIXELSV2E"}
1606+
)
1607+
1608+
16041609
def has_neuropixels_probes(settings_file: str | Path, stream_name: str | None = None) -> bool:
16051610
"""
1606-
Return True if the Open Ephys settings file contains parseable Neuropixels
1607-
probe geometry.
1611+
Return True if the Open Ephys settings file contains Neuropixels probe
1612+
geometry elements.
16081613
1609-
Detection is element-based: the function parses the settings file using the
1610-
same path as :func:`read_openephys_neuropixels` and returns True only when
1611-
at least one ``<NP_PROBE>`` (or ONIX equivalent ``<NEUROPIXELSV1E>`` /
1612-
``<NEUROPIXELSV1F>`` / ``<NEUROPIXELSV2E>``) element is present under a
1613-
Neuropixels-capable processor. This is the ground-truth signal that the
1614-
reader will be able to build a probe from the file.
1614+
Detection is element-based: the function scans the settings XML for
1615+
``<NP_PROBE>`` (Neuropix-PXI / OneBox) or the ONIX equivalents
1616+
``<NEUROPIXELSV1E>`` / ``<NEUROPIXELSV1F>`` / ``<NEUROPIXELSV2E>``. The
1617+
presence of any of these is the ground-truth signal that Neuropixels
1618+
geometry is described in the file, independent of processor names. This
1619+
is robust to ONIX streams that can carry non-Neuropixels probes and to
1620+
new Neuropixels-capable plugins.
16151621
16161622
Intended use: callers that route heterogeneous streams (e.g. Open Ephys
16171623
recordings mixing Intan / NI-DAQmx / Neuropixels) can gate the call to
1618-
:func:`read_openephys_neuropixels` on this helper and skip probe attachment
1619-
for non-Neuropixels streams.
1624+
:func:`read_openephys_neuropixels` on this helper and skip probe
1625+
attachment for non-Neuropixels streams.
16201626
16211627
Parameters
16221628
----------
16231629
settings_file : str or Path
16241630
Path to the Open Ephys settings.xml file.
16251631
stream_name : str or None
1626-
If provided, only return True when a Neuropixels probe matching this
1627-
stream name is present. Matching mirrors the selection logic in
1628-
:func:`read_openephys_neuropixels`: a probe's name must appear as a
1629-
substring of ``stream_name`` (so ``"ProbeC"`` matches
1632+
If provided, only return True when a Neuropixels probe element lives
1633+
under a processor whose STREAM names match ``stream_name``. Matching
1634+
mirrors the selection logic in :func:`read_openephys_neuropixels`: a
1635+
probe's STREAM name (with ``-AP`` / ``-LFP`` stripped) must appear as
1636+
a substring of ``stream_name`` (so ``"ProbeC"`` matches
16301637
``"Neuropix-PXI-100.ProbeC-AP"``). If None, returns True whenever any
1631-
Neuropixels probe is present.
1638+
Neuropixels probe element is present.
16321639
16331640
Returns
16341641
-------
16351642
bool
1636-
True if Neuropixels probe geometry is present (and matches
1637-
``stream_name`` when given), False otherwise.
16381643
"""
1644+
ET = import_safely("xml.etree.ElementTree")
16391645
try:
1640-
probes_info = _parse_openephys_settings(settings_file, raise_error=False)
1646+
root = ET.parse(str(settings_file)).getroot()
16411647
except Exception:
16421648
return False
1643-
if not probes_info:
1644-
return False
1645-
if stream_name is None:
1646-
return True
1647-
return any(info["name"] in stream_name for info in probes_info)
1649+
1650+
for processor in root.iter("PROCESSOR"):
1651+
if not any(e.tag in _NP_PROBE_ELEMENT_TAGS for e in processor.iter()):
1652+
continue
1653+
if stream_name is None:
1654+
return True
1655+
for stream_field in processor.findall("STREAM"):
1656+
name = stream_field.attrib.get("name", "")
1657+
if "ADC" in name:
1658+
continue
1659+
probe_name = name.replace("-AP", "").replace("-LFP", "")
1660+
if probe_name and probe_name in stream_name:
1661+
return True
1662+
return False
16481663

16491664

16501665
def get_saved_channel_indices_from_openephys_settings(settings_file: str | Path, stream_name: str) -> np.ndarray | None:

tests/test_io/test_openephys.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -727,25 +727,6 @@ def test_has_neuropixels_probes_stream_match():
727727
assert has_neuropixels_probes(settings, stream_name="Rhythm_FPGA-100.0") is False
728728

729729

730-
def test_has_neuropixels_probes_negative(tmp_path):
731-
# A settings.xml with only a non-Neuropixels processor (e.g. Rhythm FPGA / Intan)
732-
# must return False. This is the routing case that motivates the helper.
733-
settings = tmp_path / "settings.xml"
734-
settings.write_text(
735-
"""<?xml version="1.0"?>
736-
<SETTINGS>
737-
<INFO><VERSION>0.6.0</VERSION></INFO>
738-
<SIGNALCHAIN>
739-
<PROCESSOR name="Sources/Rhythm FPGA" pluginName="Rhythm FPGA">
740-
<EDITOR/>
741-
</PROCESSOR>
742-
</SIGNALCHAIN>
743-
</SETTINGS>
744-
"""
745-
)
746-
assert has_neuropixels_probes(settings) is False
747-
748-
749730
if __name__ == "__main__":
750731
# test_multiple_probes()
751732
# test_NP_Ultra()

0 commit comments

Comments
 (0)