Skip to content

channel_stats_buggy

spyglass_workshop.channel_stats_buggy

Channel statistics — buggy version for the debugging exercise.

Contains three intentional bugs, each requiring a different debugger technique. Fix them in order — each fix reveals the next problem.

Bug 1 — TypeError from a builtin (fires on every channel immediately) _mean references len as a value instead of calling len(values). Python divides by the built-in function object rather than by a number, raising TypeError before any channel is processed. The fix is a single pair of parentheses.

Bug 2 — missing guard clause (fires after Bug 1 is fixed) _z_scores divides every sample by sigma without first checking whether sigma is zero. Because Bug 3 makes _variance return 0.0 for every channel, all channels have sigma == 0 until that is also fixed. Inspect sigma in the Variables panel to confirm it is 0.0, then add an early-return guard.

Bug 3 — loop accumulation error (produces wrong values after Bug 2 is fixed) _variance uses sq_devs + [...] inside the loop. The + operator creates a new list on each iteration but does not update sq_devs, which stays [] for the entire loop. sum([]) / n is always 0.0, so every channel reports std == 0.0. Set a breakpoint on the sq_devs + line, step through the loop, and watch sq_devs in the Variables panel — it never grows. Fix with sq_devs.append(...) or sq_devs += [...].

Run the test suite to verify all three fixes::

pytest tests/test_channel_stats_buggy.py -v

dummy_function(list_of_list_of_list_of_floats)

This is a dummy function to demonstrate docstring folding.

Source code in src/spyglass_workshop/channel_stats_buggy.py
42
43
44
45
46
47
48
49
def dummy_function(
    list_of_list_of_list_of_floats: list[list[list[float]]],
) -> None:
    """This is a dummy function to demonstrate docstring folding."""
    for list_of_list_of_floats in list_of_list_of_list_of_floats:
        for list_of_floats in list_of_list_of_floats:
            for float_value in list_of_floats:
                print(float_value)

summarize(channels)

Return summary statistics for each channel in a multi-channel recording.

Computes per-channel mean, population standard deviation, and z-scores. Channels are processed independently and may have different lengths.

Parameters:

Name Type Description Default
channels list[list[float]]

Each inner list is one channel's raw sample values.

required

Returns:

Type Description
dict[int, dict]

Mapping from channel index (0-based) to a statistics dict with keys:

"mean" : float Arithmetic mean of the channel samples. "std" : float Population standard deviation (0.0 for flat signals). "z_scores" : list[float] Z-scored copy of the channel; all 0.0 for flat signals.

Raises:

Type Description
ZeroDivisionError

If any channel is empty (propagated from :func:_mean).

Notes

Channels that contain only a single repeated value (e.g. a dead electrode) will have std == 0 and z_scores consisting entirely of 0.0 once all bugs in this module are fixed.

Source code in src/spyglass_workshop/channel_stats_buggy.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
def summarize(channels):
    """Return summary statistics for each channel in a multi-channel recording.

    Computes per-channel mean, population standard deviation, and z-scores.
    Channels are processed independently and may have different lengths.

    Parameters
    ----------
    channels : list[list[float]]
        Each inner list is one channel's raw sample values.

    Returns
    -------
    dict[int, dict]
        Mapping from channel index (0-based) to a statistics dict with keys:

        ``"mean"`` : float
            Arithmetic mean of the channel samples.
        ``"std"`` : float
            Population standard deviation (``0.0`` for flat signals).
        ``"z_scores"`` : list[float]
            Z-scored copy of the channel; all ``0.0`` for flat signals.

    Raises
    ------
    ZeroDivisionError
        If any channel is empty (propagated from :func:`_mean`).

    Notes
    -----
    Channels that contain only a single repeated value (e.g. a dead
    electrode) will have ``std == 0`` and ``z_scores`` consisting entirely
    of ``0.0`` once all bugs in this module are fixed.
    """
    return {i: _channel_stats(ch) for i, ch in enumerate(channels)}